4dc73591678aeb6aeea474cdde438b159e939669
[nonrtric.git] / service-exposure / rapps-rapp-invoker.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
7 //   Licensed under the Apache License, Version 2.0 (the "License");
8 //   you may not use this file except in compliance with the License.
9 //   You may obtain a copy of the License at
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
13 //   Unless required by applicable law or agreed to in writing, software
14 //   distributed under the License is distributed on an "AS IS" BASIS,
15 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 //   See the License for the specific language governing permissions and
17 //   limitations under the License.
18 //   ========================LICENSE_END===================================
19 //
20
21 package main
22
23 import (
24         "bytes"
25         "context"
26         "encoding/json"
27         "flag"
28         "fmt"
29         "io/ioutil"
30         metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31         kubernetes "k8s.io/client-go/kubernetes"
32         "k8s.io/client-go/rest"
33         "net/http"
34         "net/url"
35         "strings"
36         "time"
37 )
38
39 type Jwttoken struct {
40         Access_token       string
41         Expires_in         int
42         Refresh_expires_in int
43         Refresh_token      string
44         Token_type         string
45         Not_before_policy  int
46         Session_state      string
47         Scope              string
48 }
49
50 var gatewayHost string
51 var gatewayPort string
52 var keycloakHost string
53 var keycloakPort string
54 var securityEnabled string
55 var useGateway string
56 var role string
57 var rapp string
58 var methods string
59 var healthy bool = true
60 var ttime time.Time 
61 var jwt Jwttoken
62
63 const (
64   namespace = "istio-nonrtric"
65 )
66
67 func getToken(secretName string) string {
68         if ttime.Before(time.Now()) {
69                 clientSecret, clientId, realmName := getSecret(secretName)
70                 keycloakUrl := "http://" + keycloakHost + ":" + keycloakPort + "/auth/realms/" + realmName + "/protocol/openid-connect/token"
71                 resp, err := http.PostForm(keycloakUrl,
72                         url.Values{"client_secret": {clientSecret}, "grant_type": {"client_credentials"}, "client_id": {clientId}})
73                 if err != nil {
74                         fmt.Println(err)
75                         panic("Something wrong with the credentials or url ")
76                 }
77                 defer resp.Body.Close()
78                 body, err := ioutil.ReadAll(resp.Body)
79                 json.Unmarshal([]byte(body), &jwt)
80                 ttime = time.Now()
81                 ttime = ttime.Add(time.Second * time.Duration(jwt.Expires_in))
82         }
83         return jwt.Access_token 
84 }
85
86 func getSecret(secretName string) (string, string, string) {
87         clientset := connectToK8s()
88         res, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
89         if err != nil {
90                 fmt.Println(err.Error())
91         }
92         return string(res.Data["client_secret"]), string(res.Data["client_id"]), string(res.Data["realm"])
93 }
94
95 func MakeRequest(client *http.Client, prefix string, method string, ch chan string) {
96         var service = strings.Split(prefix, "/")[1]
97         var gatewayUrl = "http://" + gatewayHost + ":" + gatewayPort
98         var token = ""
99         var jsonValue []byte = []byte{}
100         var restUrl string = ""
101
102         if securityEnabled == "true" {
103                 secretName := role + "-secret"
104                 token = getToken(secretName)
105         } else {
106                 useGateway = "N"
107         }
108
109         if strings.ToUpper(useGateway) != "Y" {
110                 gatewayUrl = "http://" + service + "."+namespace+":80"
111                 prefix = ""
112         }
113
114         restUrl = gatewayUrl + prefix
115
116         req, err := http.NewRequest(method, restUrl, bytes.NewBuffer(jsonValue))
117         if err != nil {
118                 fmt.Printf("Got error %s", err.Error())
119         }
120         req.Header.Set("Content-type", "application/json")
121         req.Header.Set("Authorization", "Bearer "+token)
122
123         resp, err := client.Do(req)
124         if err != nil {
125                 fmt.Printf("Got error %s", err.Error())
126         }
127         defer resp.Body.Close()
128         body, _ := ioutil.ReadAll(resp.Body)
129         respString := string(body[:])
130         if respString == "RBAC: access denied" {
131                 respString += " for " + service + " " + strings.ToLower(method) + " request"
132         }
133         fmt.Printf("Received response for %s %s request - %s\n", service, strings.ToLower(method), respString)
134         ch <- prefix + "," + method
135 }
136
137 func connectToK8s() *kubernetes.Clientset {
138         config, err := rest.InClusterConfig()
139         if err != nil {
140                 fmt.Println("failed to create K8s config")
141         }
142
143         clientset, err := kubernetes.NewForConfig(config)
144         if err != nil {
145                 fmt.Println("Failed to create K8s clientset")
146         }
147
148         return clientset
149 }
150
151 func health(res http.ResponseWriter, req *http.Request) {
152         if healthy {
153                 res.WriteHeader(http.StatusOK)
154                 res.Write([]byte("healthy"))
155         } else {
156                 res.WriteHeader(http.StatusInternalServerError)
157                 res.Write([]byte("unhealthy"))
158         }
159 }
160
161 func main() {
162         ttime = time.Now()
163         time.Sleep(1 * time.Second)
164         flag.StringVar(&gatewayHost, "gatewayHost", "istio-ingressgateway.istio-system", "Gateway Host")
165         flag.StringVar(&gatewayPort, "gatewayPort", "80", "Gateway Port")
166         flag.StringVar(&keycloakHost, "keycloakHost", "istio-ingressgateway.istio-system", "Keycloak Host")
167         flag.StringVar(&keycloakPort, "keycloakPort", "80", "Keycloak Port")
168         flag.StringVar(&useGateway, "useGateway", "Y", "Connect to services through API gateway")
169         flag.StringVar(&securityEnabled, "securityEnabled", "true", "Security is required to use this application")
170         flag.StringVar(&role, "role", "provider-viewer", "Role granted to application")
171         flag.StringVar(&rapp, "rapp", "rapp-provider", "Name of rapp to invoke")
172         flag.StringVar(&methods, "methods", "GET", "Methods to access application")
173         flag.Parse()
174
175         healthHandler := http.HandlerFunc(health)
176         http.Handle("/health", healthHandler)
177         go func() {
178                 http.ListenAndServe(":9000", nil)
179         }()
180
181         client := &http.Client{
182                 Timeout: time.Second * 10,
183         }
184
185         ch := make(chan string)
186         var prefixArray []string = []string{"/" + rapp}
187         var methodArray []string = []string{methods}
188         for _, prefix := range prefixArray {
189                 for _, method := range methodArray {
190                         go MakeRequest(client, prefix, method, ch)
191                 }
192         }
193
194         ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)
195
196         for r := range ch {
197                 go func(resp string) {
198                         time.Sleep(10 * time.Second)
199                         elements := strings.Split(resp, ",")
200                         prefix := elements[0]
201                         method := elements[1]
202                         MakeRequest(client, prefix, method, ch)
203                 }(r)
204         }
205
206 }