[RIC-A-F14] Provide Platform Healthcheck for xApps via O1
[ric-plt/o1.git] / agent / pkg / sbi / sbi.go
1 /*
2 ==================================================================================
3   Copyright (c) 2019 AT&T Intellectual Property.
4   Copyright (c) 2019 Nokia
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 package sbi
21
22 import (
23         "bytes"
24         "fmt"
25         httptransport "github.com/go-openapi/runtime/client"
26         "github.com/go-openapi/strfmt"
27         "os/exec"
28         "regexp"
29         "strings"
30         "time"
31
32         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
33         apiclient "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/appmgrclient"
34         apixapp "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/appmgrclient/xapp"
35         apimodel "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/appmgrmodel"
36 )
37
38 type PodStatus struct {
39         Name   string
40         Health string
41         Status string
42 }
43
44 var log = xapp.Logger
45
46 func NewSBIClient(host, baseUrl string, prot []string, timo int) *SBIClient {
47         return &SBIClient{host, baseUrl, prot, time.Duration(timo) * time.Second}
48 }
49
50 func (s *SBIClient) CreateTransport() *apiclient.RICAppmgr {
51         return apiclient.New(httptransport.New(s.host, s.baseUrl, s.prot), strfmt.Default)
52 }
53
54 func (s *SBIClient) BuildXappDescriptor(name, namespace, release, version string) *apimodel.XappDescriptor {
55         return &apimodel.XappDescriptor{
56                 XappName:    &name,
57                 HelmVersion: version,
58                 ReleaseName: release,
59                 Namespace:   namespace,
60         }
61 }
62
63 func (s *SBIClient) DeployXapp(xappDesc *apimodel.XappDescriptor) error {
64         params := apixapp.NewDeployXappParamsWithTimeout(s.timeout).WithXappDescriptor(xappDesc)
65         log.Info("SBI: DeployXapp=%v", params)
66
67         result, err := s.CreateTransport().Xapp.DeployXapp(params)
68         if err != nil {
69                 log.Error("SBI: DeployXapp unsuccessful: %v", err)
70         } else {
71                 log.Info("SBI: DeployXapp successful: payload=%v", result.Payload)
72         }
73         return err
74 }
75
76 func (s *SBIClient) UndeployXapp(xappDesc *apimodel.XappDescriptor) error {
77         name := *xappDesc.XappName
78         if xappDesc.ReleaseName != "" {
79                 name = xappDesc.ReleaseName
80         }
81
82         params := apixapp.NewUndeployXappParamsWithTimeout(s.timeout).WithXAppName(name)
83         log.Info("SBI: UndeployXapp=%v", params)
84
85         result, err := s.CreateTransport().Xapp.UndeployXapp(params)
86         if err != nil {
87                 log.Error("SBI: UndeployXapp unsuccessful: %v", err)
88         } else {
89                 log.Info("SBI: UndeployXapp successful: payload=%v", result)
90         }
91         return err
92 }
93
94 func (s *SBIClient) GetDeployedXapps() error {
95         params := apixapp.NewGetAllXappsParamsWithTimeout(s.timeout)
96         result, err := s.CreateTransport().Xapp.GetAllXapps(params)
97         if err != nil {
98                 log.Error("GET unsuccessful: %v", err)
99         } else {
100                 log.Info("GET successful: payload=%v", result.Payload)
101         }
102         return err
103 }
104
105 func (s *SBIClient) BuildXappConfig(name, namespace string, configData interface{}) *apimodel.XAppConfig {
106         metadata := &apimodel.ConfigMetadata{
107                 XappName:  &name,
108                 Namespace: &namespace,
109         }
110
111         return &apimodel.XAppConfig{
112                 Metadata: metadata,
113                 Config:   configData,
114         }
115 }
116
117 func (s *SBIClient) ModifyXappConfig(xappConfig *apimodel.XAppConfig) error {
118         params := apixapp.NewModifyXappConfigParamsWithTimeout(s.timeout).WithXAppConfig(xappConfig)
119         result, err := s.CreateTransport().Xapp.ModifyXappConfig(params)
120         if err != nil {
121                 log.Error("SBI: ModifyXappConfig unsuccessful: %v", err)
122         } else {
123                 log.Info("SBI: ModifyXappConfig successful: payload=%v", result.Payload)
124         }
125         return err
126 }
127
128 func (s *SBIClient) GetAllPodStatus(namespace string) ([]PodStatus, error) {
129         output, err := s.RunCommand(fmt.Sprintf("/usr/local/bin/kubectl get pod -n %s", namespace))
130         if err != nil {
131                 return []PodStatus{}, err
132         }
133
134         podStatusList := []PodStatus{}
135         var readyStr string
136         re := regexp.MustCompile(fmt.Sprintf(`%s-.*`, namespace))
137         podList := re.FindAllStringSubmatch(string(output), -1)
138         if podList != nil {
139                 for _, pod := range podList {
140                         p := PodStatus{}
141                         fmt.Sscanf(pod[0], "%s %s %s", &p.Name, &readyStr, &p.Status)
142                         p.Name = strings.Split(p.Name, "-")[1]
143                         p.Health = s.GetHealthState(readyStr)
144
145                         podStatusList = append(podStatusList, p)
146                 }
147         }
148         return podStatusList, nil
149 }
150
151 func (s *SBIClient) GetHealthState(ready string) (state string) {
152         result := strings.Split(ready, "/")
153         if len(result) < 2 {
154                 return "unavailable"
155         }
156
157         if result[0] == result[1] {
158                 state = "healthy"
159         } else {
160                 state = "unhealthy"
161         }
162         return
163 }
164
165 func (s *SBIClient) RunCommand(args string) (string, error) {
166         return CommandExec(args)
167 }
168
169 var CommandExec = func(args string) (string, error) {
170         cmd := exec.Command("/bin/sh", "-c", args)
171         var stdout bytes.Buffer
172         var stderr bytes.Buffer
173         cmd.Stdout = &stdout
174         cmd.Stderr = &stderr
175
176         xapp.Logger.Debug("Running command: '%s'", cmd)
177         if err := cmd.Run(); err != nil {
178                 xapp.Logger.Error("Command failed (%s): %v - %s", cmd, err.Error(), stderr.String())
179                 return "", err
180         }
181         xapp.Logger.Debug("Command executed successfully!")
182         return stdout.String(), nil
183 }