409c6e9224a4b1222d31c9befee17151abc87bd8
[icn/sdwan.git] /
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (c) 2020 Intel Corporation
3
4 package controller
5
6 import (
7         "encoding/json"
8         "strings"
9
10         "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"
11         log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
12         rpc "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc"
13         mtypes "github.com/open-ness/EMCO/src/orchestrator/pkg/module/types"
14         pkgerrors "github.com/pkg/errors"
15 )
16
17 // Controller contains the parameters needed for Controllers
18 // It implements the interface for managing the Controllers
19 type Controller struct {
20         Metadata mtypes.Metadata `json:"metadata"`
21         Spec     ControllerSpec  `json:"spec"`
22 }
23
24 type ControllerSpec struct {
25         Host     string `json:"host"`
26         Port     int    `json:"port"`
27         Type     string `json:"type"`
28         Priority int    `json:"priority"`
29 }
30
31 const MinControllerPriority = 1
32 const MaxControllerPriority = 1000000
33 const CONTROLLER_TYPE_ACTION string = "action"
34 const CONTROLLER_TYPE_PLACEMENT string = "placement"
35
36 var CONTROLLER_TYPES = [...]string{CONTROLLER_TYPE_ACTION, CONTROLLER_TYPE_PLACEMENT}
37
38 // ControllerKey is the key structure that is used in the database
39 type ControllerKey struct {
40         ControllerName string `json:"controller-name"`
41 }
42
43 // We will use json marshalling to convert to string to
44 // preserve the underlying structure.
45 func (mk ControllerKey) String() string {
46         out, err := json.Marshal(mk)
47         if err != nil {
48                 return ""
49         }
50
51         return string(out)
52 }
53
54 // ControllerManager is an interface exposes the Controller functionality
55 type ControllerManager interface {
56         CreateController(ms Controller, mayExist bool) (Controller, error)
57         GetController(name string) (Controller, error)
58         GetControllers() ([]Controller, error)
59         InitControllers()
60         DeleteController(name string) error
61 }
62
63 // ControllerClient implements the Manager
64 // It will also be used to maintain some localized state
65 type ControllerClient struct {
66         collectionName string
67         tagMeta        string
68 }
69
70 // NewControllerClient returns an instance of the ControllerClient
71 // which implements the Manager
72 func NewControllerClient() *ControllerClient {
73         return &ControllerClient{
74                 collectionName: "controller",
75                 tagMeta:        "controllermetadata",
76         }
77 }
78
79 // CreateController a new collection based on the Controller
80 func (mc *ControllerClient) CreateController(m Controller, mayExist bool) (Controller, error) {
81
82         log.Info("CreateController .. start", log.Fields{"Controller": m, "exists": mayExist})
83
84         //Construct the composite key to select the entry
85         key := ControllerKey{
86                 ControllerName: m.Metadata.Name,
87         }
88
89         //Check if this Controller already exists
90         _, err := mc.GetController(m.Metadata.Name)
91         if err == nil && !mayExist {
92                 return Controller{}, pkgerrors.New("Controller already exists")
93         }
94
95         err = db.DBconn.Insert(mc.collectionName, key, nil, mc.tagMeta, m)
96         if err != nil {
97                 return Controller{}, pkgerrors.Wrap(err, "Creating DB Entry")
98         }
99
100         // send message to create/update the  rpc connection
101         rpc.UpdateRpcConn(m.Metadata.Name, m.Spec.Host, m.Spec.Port)
102
103         log.Info("CreateController .. end", log.Fields{"Controller": m, "exists": mayExist})
104         return m, nil
105 }
106
107 // GetController returns the Controller for corresponding name
108 func (mc *ControllerClient) GetController(name string) (Controller, error) {
109
110         //Construct the composite key to select the entry
111         key := ControllerKey{
112                 ControllerName: name,
113         }
114         value, err := db.DBconn.Find(mc.collectionName, key, mc.tagMeta)
115         if err != nil {
116                 return Controller{}, pkgerrors.Wrap(err, "db Find error")
117         } else if len(value) == 0 {
118                 return Controller{}, pkgerrors.New("Controller not found")
119         }
120
121         if value != nil {
122                 microserv := Controller{}
123                 err = db.DBconn.Unmarshal(value[0], &microserv)
124                 if err != nil {
125                         return Controller{}, pkgerrors.Wrap(err, "Unmarshaling Value")
126                 }
127                 return microserv, nil
128         }
129
130         return Controller{}, pkgerrors.New("Error getting Controller")
131 }
132
133 // GetControllers returns all the  Controllers that are registered
134 func (mc *ControllerClient) GetControllers() ([]Controller, error) {
135
136         //Construct the composite key to select the entry
137         key := ControllerKey{
138                 ControllerName: "",
139         }
140
141         var resp []Controller
142         values, err := db.DBconn.Find(mc.collectionName, key, mc.tagMeta)
143         if err != nil {
144                 return []Controller{}, pkgerrors.Wrap(err, "db Find error")
145         }
146
147         for _, value := range values {
148                 microserv := Controller{}
149                 err = db.DBconn.Unmarshal(value, &microserv)
150                 if err != nil {
151                         return []Controller{}, pkgerrors.Wrap(err, "Unmarshaling Value")
152                 }
153
154                 resp = append(resp, microserv)
155         }
156
157         return resp, nil
158 }
159
160 // DeleteController the  Controller from database
161 func (mc *ControllerClient) DeleteController(name string) error {
162
163         //Construct the composite key to select the entry
164         key := ControllerKey{
165                 ControllerName: name,
166         }
167         err := db.DBconn.Remove(mc.collectionName, key)
168         if err != nil {
169                 if strings.Contains(err.Error(), "Error finding:") {
170                         return pkgerrors.Wrap(err, "db Remove error - not found")
171                 } else if strings.Contains(err.Error(), "Can't delete parent without deleting child") {
172                         return pkgerrors.Wrap(err, "db Remove error - conflict")
173                 } else {
174                         return pkgerrors.Wrap(err, "db Remove error - general")
175                 }
176         }
177
178         // send message to close rpc connection
179         rpc.RemoveRpcConn(name)
180
181         return nil
182 }
183
184 // InitControllers initializes connctions for controllers in the DB
185 func (mc *ControllerClient) InitControllers() {
186         vals, _ := mc.GetControllers()
187         for _, v := range vals {
188                 log.Info("Initializing RPC connection for controller", log.Fields{
189                         "Controller": v.Metadata.Name,
190                 })
191                 rpc.UpdateRpcConn(v.Metadata.Name, v.Spec.Host, v.Spec.Port)
192         }
193 }