blob: 2de584cbeafed223a0da870433a05799c7c02a1a [file] [log] [blame]
Elia Battistona1333642022-07-27 12:17:24 +00001/*
2* Copyright 2022-present Open Networking Foundation
3
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7
8* http://www.apache.org/licenses/LICENSE-2.0
9
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15 */
16
17package clients
18
19import (
20 "context"
21 "encoding/json"
22 "fmt"
23 "io"
24 "net/http"
25 "time"
26
27 "github.com/opencord/voltha-lib-go/v7/pkg/log"
28)
29
30const (
31 onosHttpRequestTimeout = time.Second * 10
32 onosBackoffInterval = time.Second * 10
33)
34
35type OnosClient struct {
36 httpClient *http.Client
37 endpoint string
38 username string
39 password string
40}
41
42type RestResponse struct {
43 Body string
44 Code int
45}
46
47// Creates a new olt app client
48func NewOnosClient(endpoint string, user string, pass string) *OnosClient {
49 return &OnosClient{
50 httpClient: &http.Client{
51 Timeout: onosHttpRequestTimeout,
52 },
53 endpoint: endpoint,
54 username: user,
55 password: pass,
56 }
57}
58
59func (c *OnosClient) CheckConnection(ctx context.Context) error {
60 logger.Debugw(ctx, "checking-connection-to-onos-olt-app-api", log.Fields{"endpoint": c.endpoint})
61
62 for {
63 if resp, err := c.GetStatus(); err == nil {
64 logger.Debug(ctx, "onos-olt-app-api-reachable")
65 break
66 } else {
67 logger.Warnw(ctx, "onos-olt-app-api-not-ready", log.Fields{
68 "err": err,
69 "response": resp,
70 })
71 }
72
73 //Wait a bit before trying again
74 select {
75 case <-ctx.Done():
76 return fmt.Errorf("onos-olt-app-connection-stopped-due-to-context-done")
77 case <-time.After(onosBackoffInterval):
78 continue
79 }
80 }
81
82 return nil
83}
84
85func (c *OnosClient) makeRequest(method string, url string) (RestResponse, error) {
86 result := RestResponse{Code: 0}
87
88 req, err := http.NewRequest(method, url, nil)
89 if err != nil {
90 return result, fmt.Errorf("cannot-create-request: %s", err)
91 }
92
93 req.SetBasicAuth(c.username, c.password)
94
95 resp, err := c.httpClient.Do(req)
96 if err != nil {
97 return result, fmt.Errorf("cannot-get-response: %s", err)
98 }
99 defer resp.Body.Close()
100
101 buffer, err := io.ReadAll(resp.Body)
102 if err != nil {
103 return result, fmt.Errorf("error-while-reading-response-body: %s", err)
104 }
105
106 result.Body = string(buffer)
107 result.Code = resp.StatusCode
108
109 if result.Code != http.StatusOK {
110 return result, fmt.Errorf("status-code-not-ok: %s %s %d", method, url, result.Code)
111 }
112
113 return result, nil
114}
115
116///////////////////////////////////////////////////////////////////////// ONOS OLT app APIs
117
118func (c *OnosClient) GetStatus() (RestResponse, error) {
119 method := http.MethodGet
120 url := fmt.Sprintf("http://%s/onos/olt/oltapp/status", c.endpoint)
121
122 return c.makeRequest(method, url)
123}
124
125func (c *OnosClient) ProvisionService(portName string, sTag string, cTag string, technologyProfileId string) (RestResponse, error) {
126 method := http.MethodPost
127 url := fmt.Sprintf("http://%s/onos/olt/oltapp/services/%s/%s/%s/%s", c.endpoint, portName, sTag, cTag, technologyProfileId)
128
129 return c.makeRequest(method, url)
130}
131
132func (c *OnosClient) RemoveService(portName string, sTag string, cTag string, trafficProfileId string) (RestResponse, error) {
133 method := http.MethodDelete
134 url := fmt.Sprintf("http://%s/onos/olt/oltapp/services/%s/%s/%s/%s", c.endpoint, portName, sTag, cTag, trafficProfileId)
135
136 return c.makeRequest(method, url)
137}
138
139type ProgrammedSubscriber struct {
140 Location string `json:"location"`
141 TagInfo SadisUniTag `json:"tagInfo"`
142}
143
144type SadisUniTag struct {
145 UniTagMatch int `json:"uniTagMatch,omitempty"`
146 PonCTag int `json:"ponCTag,omitempty"`
147 PonSTag int `json:"ponSTag,omitempty"`
148 TechnologyProfileID int `json:"technologyProfileId,omitempty"`
149 UpstreamBandwidthProfile string `json:"upstreamBandwidthProfile,omitempty"`
150 UpstreamOltBandwidthProfile string `json:"upstreamOltBandwidthProfile,omitempty"`
151 DownstreamBandwidthProfile string `json:"downstreamBandwidthProfile,omitempty"`
152 DownstreamOltBandwidthProfile string `json:"downstreamOltBandwidthProfile,omitempty"`
153 IsDhcpRequired bool `json:"isDhcpRequired,omitempty"`
154 IsIgmpRequired bool `json:"isIgmpRequired,omitempty"`
155 IsPPPoERequired bool `json:"isPppoeRequired,omitempty"`
156 ConfiguredMacAddress string `json:"configuredMacAddress,omitempty"`
157 EnableMacLearning bool `json:"enableMacLearning,omitempty"`
158 UsPonCTagPriority int `json:"usPonCTagPriority,omitempty"`
159 UsPonSTagPriority int `json:"usPonSTagPriority,omitempty"`
160 DsPonCTagPriority int `json:"dsPonCTagPriority,omitempty"`
161 DsPonSTagPriority int `json:"dsPonSTagPriority,omitempty"`
162 ServiceName string `json:"serviceName,omitempty"`
163}
164
165func (c *OnosClient) GetProgrammedSubscribers() ([]ProgrammedSubscriber, error) {
166 method := http.MethodGet
167 url := fmt.Sprintf("http://%s/onos/olt/oltapp/programmed-subscribers", c.endpoint)
168
169 response, err := c.makeRequest(method, url)
170 if err != nil {
171 return nil, err
172 }
173
174 var subscribers struct {
175 Entries []ProgrammedSubscriber `json:"entries"`
176 }
177 err = json.Unmarshal([]byte(response.Body), &subscribers)
178 if err != nil {
179 return nil, err
180 }
181
182 return subscribers.Entries, nil
183}
184
185///////////////////////////////////////////////////////////////////////// ONOS Core APIs
186
187type OnosPort struct {
188 Element string `json:"element"` //Device ID
189 Port string `json:"port"` //Port number
190 IsEnabled bool `json:"isEnabled"`
191 Type string `json:"type"`
192 PortSpeed uint `json:"portSpeed"`
193 Annotations map[string]string `json:"annotations"`
194}
195
196func (c *OnosClient) GetPorts() ([]OnosPort, error) {
197 method := http.MethodGet
198 url := fmt.Sprintf("http://%s/onos/v1/devices/ports", c.endpoint)
199
200 response, err := c.makeRequest(method, url)
201 if err != nil {
202 return nil, err
203 }
204
205 var ports struct {
206 Ports []OnosPort `json:"ports"`
207 }
208 err = json.Unmarshal([]byte(response.Body), &ports)
209 if err != nil {
210 return nil, err
211 }
212
213 return ports.Ports, nil
214}
215
216///////////////////////////////////////////////////////////////////////// ONOS SADIS APIs
217
218type BandwidthProfile struct {
219 Id string `json:"id"`
220 Cir int64 `json:"cir"`
221 Cbs string `json:"cbs"`
222 Air int64 `json:"air"`
223 Gir int64 `json:"gir"`
224 Eir int64 `json:"eir"`
225 Ebs string `json:"ebs"`
226 Pir int64 `json:"pir"`
227 Pbs string `json:"pbs"`
228}
229
230func (c *OnosClient) GetBandwidthProfile(id string) (*BandwidthProfile, error) {
231 method := http.MethodGet
232 url := fmt.Sprintf("http://%s/onos/sadis/bandwidthprofile/%s", c.endpoint, id)
233
234 response, err := c.makeRequest(method, url)
235 if err != nil {
236 return nil, err
237 }
238
239 var bwProfiles struct {
240 Entry []BandwidthProfile `json:"entry"`
241 }
242 err = json.Unmarshal([]byte(response.Body), &bwProfiles)
243 if err != nil {
244 return nil, err
245 }
246
247 //The response has a list, but always returns one item
248 //Verify this is correct and return it
249 if len(bwProfiles.Entry) != 1 {
250 return nil, fmt.Errorf("unexpected-number-of-bw-profile-entries: id=%s len=%d", id, len(bwProfiles.Entry))
251 }
252
253 return &bwProfiles.Entry[0], nil
254}