First version of service exposure
[nonrtric.git] / service-exposure / rapps-rapp-invoker.go
diff --git a/service-exposure/rapps-rapp-invoker.go b/service-exposure/rapps-rapp-invoker.go
new file mode 100644 (file)
index 0000000..4dc7359
--- /dev/null
@@ -0,0 +1,206 @@
+// -
+//   ========================LICENSE_START=================================
+//   O-RAN-SC
+//   %%
+//   Copyright (C) 2022: Nordix Foundation
+//   %%
+//   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.
+//   ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+       "bytes"
+       "context"
+       "encoding/json"
+       "flag"
+       "fmt"
+       "io/ioutil"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       kubernetes "k8s.io/client-go/kubernetes"
+       "k8s.io/client-go/rest"
+       "net/http"
+       "net/url"
+       "strings"
+       "time"
+)
+
+type Jwttoken struct {
+       Access_token       string
+       Expires_in         int
+       Refresh_expires_in int
+       Refresh_token      string
+       Token_type         string
+       Not_before_policy  int
+       Session_state      string
+       Scope              string
+}
+
+var gatewayHost string
+var gatewayPort string
+var keycloakHost string
+var keycloakPort string
+var securityEnabled string
+var useGateway string
+var role string
+var rapp string
+var methods string
+var healthy bool = true
+var ttime time.Time 
+var jwt Jwttoken
+
+const (
+  namespace = "istio-nonrtric"
+)
+
+func getToken(secretName string) string {
+       if ttime.Before(time.Now()) {
+               clientSecret, clientId, realmName := getSecret(secretName)
+               keycloakUrl := "http://" + keycloakHost + ":" + keycloakPort + "/auth/realms/" + realmName + "/protocol/openid-connect/token"
+               resp, err := http.PostForm(keycloakUrl,
+                       url.Values{"client_secret": {clientSecret}, "grant_type": {"client_credentials"}, "client_id": {clientId}})
+               if err != nil {
+                       fmt.Println(err)
+                       panic("Something wrong with the credentials or url ")
+               }
+               defer resp.Body.Close()
+               body, err := ioutil.ReadAll(resp.Body)
+               json.Unmarshal([]byte(body), &jwt)
+               ttime = time.Now()
+               ttime = ttime.Add(time.Second * time.Duration(jwt.Expires_in))
+       }
+       return jwt.Access_token 
+}
+
+func getSecret(secretName string) (string, string, string) {
+        clientset := connectToK8s()
+        res, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
+        if err != nil {
+                fmt.Println(err.Error())
+        }
+        return string(res.Data["client_secret"]), string(res.Data["client_id"]), string(res.Data["realm"])
+}
+
+func MakeRequest(client *http.Client, prefix string, method string, ch chan string) {
+       var service = strings.Split(prefix, "/")[1]
+       var gatewayUrl = "http://" + gatewayHost + ":" + gatewayPort
+       var token = ""
+       var jsonValue []byte = []byte{}
+       var restUrl string = ""
+
+       if securityEnabled == "true" {
+               secretName := role + "-secret"
+               token = getToken(secretName)
+       } else {
+               useGateway = "N"
+       }
+
+       if strings.ToUpper(useGateway) != "Y" {
+               gatewayUrl = "http://" + service + "."+namespace+":80"
+               prefix = ""
+       }
+
+       restUrl = gatewayUrl + prefix
+
+       req, err := http.NewRequest(method, restUrl, bytes.NewBuffer(jsonValue))
+       if err != nil {
+               fmt.Printf("Got error %s", err.Error())
+       }
+       req.Header.Set("Content-type", "application/json")
+       req.Header.Set("Authorization", "Bearer "+token)
+
+       resp, err := client.Do(req)
+       if err != nil {
+               fmt.Printf("Got error %s", err.Error())
+       }
+       defer resp.Body.Close()
+       body, _ := ioutil.ReadAll(resp.Body)
+       respString := string(body[:])
+       if respString == "RBAC: access denied" {
+               respString += " for " + service + " " + strings.ToLower(method) + " request"
+       }
+       fmt.Printf("Received response for %s %s request - %s\n", service, strings.ToLower(method), respString)
+       ch <- prefix + "," + method
+}
+
+func connectToK8s() *kubernetes.Clientset {
+       config, err := rest.InClusterConfig()
+       if err != nil {
+               fmt.Println("failed to create K8s config")
+       }
+
+       clientset, err := kubernetes.NewForConfig(config)
+       if err != nil {
+               fmt.Println("Failed to create K8s clientset")
+       }
+
+       return clientset
+}
+
+func health(res http.ResponseWriter, req *http.Request) {
+       if healthy {
+               res.WriteHeader(http.StatusOK)
+               res.Write([]byte("healthy"))
+       } else {
+               res.WriteHeader(http.StatusInternalServerError)
+               res.Write([]byte("unhealthy"))
+       }
+}
+
+func main() {
+       ttime = time.Now()
+       time.Sleep(1 * time.Second)
+       flag.StringVar(&gatewayHost, "gatewayHost", "istio-ingressgateway.istio-system", "Gateway Host")
+       flag.StringVar(&gatewayPort, "gatewayPort", "80", "Gateway Port")
+       flag.StringVar(&keycloakHost, "keycloakHost", "istio-ingressgateway.istio-system", "Keycloak Host")
+       flag.StringVar(&keycloakPort, "keycloakPort", "80", "Keycloak Port")
+       flag.StringVar(&useGateway, "useGateway", "Y", "Connect to services through API gateway")
+       flag.StringVar(&securityEnabled, "securityEnabled", "true", "Security is required to use this application")
+       flag.StringVar(&role, "role", "provider-viewer", "Role granted to application")
+       flag.StringVar(&rapp, "rapp", "rapp-provider", "Name of rapp to invoke")
+       flag.StringVar(&methods, "methods", "GET", "Methods to access application")
+       flag.Parse()
+
+       healthHandler := http.HandlerFunc(health)
+       http.Handle("/health", healthHandler)
+       go func() {
+               http.ListenAndServe(":9000", nil)
+       }()
+
+       client := &http.Client{
+               Timeout: time.Second * 10,
+       }
+
+       ch := make(chan string)
+       var prefixArray []string = []string{"/" + rapp}
+       var methodArray []string = []string{methods}
+       for _, prefix := range prefixArray {
+               for _, method := range methodArray {
+                       go MakeRequest(client, prefix, method, ch)
+               }
+       }
+
+       ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)
+
+       for r := range ch {
+               go func(resp string) {
+                       time.Sleep(10 * time.Second)
+                       elements := strings.Split(resp, ",")
+                       prefix := elements[0]
+                       method := elements[1]
+                       MakeRequest(client, prefix, method, ch)
+               }(r)
+       }
+
+}