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