diff --git a/contivModel/contivModel.go b/contivModel/contivModel.go index af80cef..9bc8c9b 100644 --- a/contivModel/contivModel.go +++ b/contivModel/contivModel.go @@ -68,6 +68,15 @@ type Global struct { NetworkInfraType string `json:"network-infra-type,omitempty"` } +type Bgp struct { + // every object has a key + Key string `json:"key,omitempty"` + + AS string `json:"AS,omitempty"` + Name string `json:"name,omitempty"` + Neighbor string `json:"neighbor,omitempty"` +} + type Network struct { // every object has a key Key string `json:"key,omitempty"` @@ -272,6 +281,7 @@ type Collections struct { apps map[string]*App endpointGroups map[string]*EndpointGroup globals map[string]*Global + Bgps map[string]*Bgp networks map[string]*Network policys map[string]*Policy rules map[string]*Rule @@ -302,6 +312,12 @@ type GlobalCallbacks interface { GlobalDelete(global *Global) error } +type BgpCallbacks interface { + BgpCreate(Bgp *Bgp) error + BgpUpdate(Bgp, params *Bgp) error + BgpDelete(Bgp *Bgp) error +} + type NetworkCallbacks interface { NetworkCreate(network *Network) error NetworkUpdate(network, params *Network) error @@ -354,6 +370,7 @@ type CallbackHandlers struct { AppCb AppCallbacks EndpointGroupCb EndpointGroupCallbacks GlobalCb GlobalCallbacks + BgpCb BgpCallbacks NetworkCb NetworkCallbacks PolicyCb PolicyCallbacks RuleCb RuleCallbacks @@ -370,6 +387,7 @@ func Init() { collections.apps = make(map[string]*App) collections.endpointGroups = make(map[string]*EndpointGroup) collections.globals = make(map[string]*Global) + collections.Bgps = make(map[string]*Bgp) collections.networks = make(map[string]*Network) collections.policys = make(map[string]*Policy) collections.rules = make(map[string]*Rule) @@ -382,6 +400,7 @@ func Init() { restoreApp() restoreEndpointGroup() restoreGlobal() + restoreBgp() restoreNetwork() restorePolicy() restoreRule() @@ -405,6 +424,10 @@ func RegisterGlobalCallbacks(handler GlobalCallbacks) { objCallbackHandler.GlobalCb = handler } +func RegisterBgpCallbacks(handler BgpCallbacks) { + objCallbackHandler.BgpCb = handler +} + func RegisterNetworkCallbacks(handler NetworkCallbacks) { objCallbackHandler.NetworkCb = handler } @@ -506,6 +529,16 @@ func AddRoutes(router *mux.Router) { router.Path(route).Methods("PUT").HandlerFunc(makeHttpHandler(httpCreateGlobal)) router.Path(route).Methods("DELETE").HandlerFunc(makeHttpHandler(httpDeleteGlobal)) + // Register Bgp + route = "/api/Bgps/{key}/" + listRoute = "/api/Bgps/" + log.Infof("Registering %s", route) + router.Path(listRoute).Methods("GET").HandlerFunc(makeHttpHandler(httpListBgps)) + router.Path(route).Methods("GET").HandlerFunc(makeHttpHandler(httpGetBgp)) + router.Path(route).Methods("POST").HandlerFunc(makeHttpHandler(httpCreateBgp)) + router.Path(route).Methods("PUT").HandlerFunc(makeHttpHandler(httpCreateBgp)) + router.Path(route).Methods("DELETE").HandlerFunc(makeHttpHandler(httpDeleteBgp)) + // Register network route = "/api/networks/{key}/" listRoute = "/api/networks/" @@ -712,6 +745,7 @@ func CreateApp(obj *App) error { func FindApp(key string) *App { obj := collections.apps[key] if obj == nil { + log.Errorf("app %s not found", key) return nil } @@ -946,6 +980,7 @@ func CreateEndpointGroup(obj *EndpointGroup) error { func FindEndpointGroup(key string) *EndpointGroup { obj := collections.endpointGroups[key] if obj == nil { + log.Errorf("endpointGroup %s not found", key) return nil } @@ -1180,6 +1215,7 @@ func CreateGlobal(obj *Global) error { func FindGlobal(key string) *Global { obj := collections.globals[key] if obj == nil { + log.Errorf("global %s not found", key) return nil } @@ -1298,6 +1334,253 @@ func ValidateGlobal(obj *Global) error { return nil } +// LIST REST call +func httpListBgps(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) { + log.Debugf("Received httpListBgps: %+v", vars) + + list := make([]*Bgp, 0) + for _, obj := range collections.Bgps { + list = append(list, obj) + } + + // Return the list + return list, nil +} + +// GET REST call +func httpGetBgp(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) { + log.Debugf("Received httpGetBgp: %+v", vars) + + key := vars["key"] + + obj := collections.Bgps[key] + if obj == nil { + log.Errorf("Bgp %s not found", key) + return nil, errors.New("Bgp not found") + } + + // Return the obj + return obj, nil +} + +// CREATE REST call +func httpCreateBgp(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) { + log.Debugf("Received httpGetBgp: %+v", vars) + + var obj Bgp + key := vars["key"] + + // Get object from the request + err := json.NewDecoder(r.Body).Decode(&obj) + if err != nil { + log.Errorf("Error decoding Bgp create request. Err %v", err) + return nil, err + } + + // set the key + obj.Key = key + + // Create the object + err = CreateBgp(&obj) + if err != nil { + log.Errorf("CreateBgp error for: %+v. Err: %v", obj, err) + return nil, err + } + + // Return the obj + return obj, nil +} + +// DELETE rest call +func httpDeleteBgp(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) { + log.Debugf("Received httpDeleteBgp: %+v", vars) + + key := vars["key"] + + // Delete the object + err := DeleteBgp(key) + if err != nil { + log.Errorf("DeleteBgp error for: %s. Err: %v", key, err) + return nil, err + } + + // Return the obj + return key, nil +} + +// Create a Bgp object +func CreateBgp(obj *Bgp) error { + // Validate parameters + err := ValidateBgp(obj) + if err != nil { + log.Errorf("ValidateBgp retruned error for: %+v. Err: %v", obj, err) + return err + } + + // Check if we handle this object + if objCallbackHandler.BgpCb == nil { + log.Errorf("No callback registered for Bgp object") + return errors.New("Invalid object type") + } + + // Check if object already exists + if collections.Bgps[obj.Key] != nil { + // Perform Update callback + err = objCallbackHandler.BgpCb.BgpUpdate(collections.Bgps[obj.Key], obj) + if err != nil { + log.Errorf("BgpUpdate retruned error for: %+v. Err: %v", obj, err) + return err + } + } else { + // save it in cache + collections.Bgps[obj.Key] = obj + + // Perform Create callback + err = objCallbackHandler.BgpCb.BgpCreate(obj) + if err != nil { + log.Errorf("BgpCreate retruned error for: %+v. Err: %v", obj, err) + delete(collections.Bgps, obj.Key) + return err + } + } + + // Write it to modeldb + err = obj.Write() + if err != nil { + log.Errorf("Error saving Bgp %s to db. Err: %v", obj.Key, err) + return err + } + + return nil +} + +// Return a pointer to Bgp from collection +func FindBgp(key string) *Bgp { + obj := collections.Bgps[key] + if obj == nil { + log.Errorf("Bgp %s not found", key) + return nil + } + + return obj +} + +// Delete a Bgp object +func DeleteBgp(key string) error { + obj := collections.Bgps[key] + if obj == nil { + log.Errorf("Bgp %s not found", key) + return errors.New("Bgp not found") + } + + // Check if we handle this object + if objCallbackHandler.BgpCb == nil { + log.Errorf("No callback registered for Bgp object") + return errors.New("Invalid object type") + } + + // Perform callback + err := objCallbackHandler.BgpCb.BgpDelete(obj) + if err != nil { + log.Errorf("BgpDelete retruned error for: %+v. Err: %v", obj, err) + return err + } + + // delete it from modeldb + err = obj.Delete() + if err != nil { + log.Errorf("Error deleting Bgp %s. Err: %v", obj.Key, err) + } + + // delete it from cache + delete(collections.Bgps, key) + + return nil +} + +func (self *Bgp) GetType() string { + return "Bgp" +} + +func (self *Bgp) GetKey() string { + return self.Key +} + +func (self *Bgp) Read() error { + if self.Key == "" { + log.Errorf("Empty key while trying to read Bgp object") + return errors.New("Empty key") + } + + return modeldb.ReadObj("Bgp", self.Key, self) +} + +func (self *Bgp) Write() error { + if self.Key == "" { + log.Errorf("Empty key while trying to Write Bgp object") + return errors.New("Empty key") + } + + return modeldb.WriteObj("Bgp", self.Key, self) +} + +func (self *Bgp) Delete() error { + if self.Key == "" { + log.Errorf("Empty key while trying to Delete Bgp object") + return errors.New("Empty key") + } + + return modeldb.DeleteObj("Bgp", self.Key) +} + +func restoreBgp() error { + strList, err := modeldb.ReadAllObj("Bgp") + if err != nil { + log.Errorf("Error reading Bgp list. Err: %v", err) + } + + for _, objStr := range strList { + // Parse the json model + var Bgp Bgp + err = json.Unmarshal([]byte(objStr), &Bgp) + if err != nil { + log.Errorf("Error parsing object %s, Err %v", objStr, err) + return err + } + + // add it to the collection + collections.Bgps[Bgp.Key] = &Bgp + } + + return nil +} + +// Validate a Bgp object +func ValidateBgp(obj *Bgp) error { + // Validate key is correct + keyStr := obj.Name + if obj.Key != keyStr { + log.Errorf("Expecting Bgp Key: %s. Got: %s", keyStr, obj.Key) + return errors.New("Invalid Key") + } + + // Validate each field + + if len(obj.AS) > 64 { + return errors.New("AS string too long") + } + + if len(obj.Name) > 256 { + return errors.New("name string too long") + } + + if len(obj.Neighbor) > 15 { + return errors.New("neighbor string too long") + } + + return nil +} + // LIST REST call func httpListNetworks(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) { log.Debugf("Received httpListNetworks: %+v", vars) @@ -1422,6 +1705,7 @@ func CreateNetwork(obj *Network) error { func FindNetwork(key string) *Network { obj := collections.networks[key] if obj == nil { + log.Errorf("network %s not found", key) return nil } @@ -1679,6 +1963,7 @@ func CreatePolicy(obj *Policy) error { func FindPolicy(key string) *Policy { obj := collections.policys[key] if obj == nil { + log.Errorf("policy %s not found", key) return nil } @@ -1913,6 +2198,7 @@ func CreateRule(obj *Rule) error { func FindRule(key string) *Rule { obj := collections.rules[key] if obj == nil { + log.Errorf("rule %s not found", key) return nil } @@ -2198,6 +2484,7 @@ func CreateService(obj *Service) error { func FindService(key string) *Service { obj := collections.services[key] if obj == nil { + log.Errorf("service %s not found", key) return nil } @@ -2432,6 +2719,7 @@ func CreateServiceInstance(obj *ServiceInstance) error { func FindServiceInstance(key string) *ServiceInstance { obj := collections.serviceInstances[key] if obj == nil { + log.Errorf("serviceInstance %s not found", key) return nil } @@ -2666,6 +2954,7 @@ func CreateTenant(obj *Tenant) error { func FindTenant(key string) *Tenant { obj := collections.tenants[key] if obj == nil { + log.Errorf("tenant %s not found", key) return nil } @@ -2931,6 +3220,7 @@ func CreateVolume(obj *Volume) error { func FindVolume(key string) *Volume { obj := collections.volumes[key] if obj == nil { + log.Errorf("volume %s not found", key) return nil } @@ -3165,6 +3455,7 @@ func CreateVolumeProfile(obj *VolumeProfile) error { func FindVolumeProfile(key string) *VolumeProfile { obj := collections.volumeProfiles[key] if obj == nil { + log.Errorf("volumeProfile %s not found", key) return nil } diff --git a/contivModel/contivModel.js b/contivModel/contivModel.js index 0704585..e250178 100644 --- a/contivModel/contivModel.js +++ b/contivModel/contivModel.js @@ -194,6 +194,65 @@ var GlobalModalView = React.createClass({ module.exports.GlobalSummaryView = GlobalSummaryView module.exports.GlobalModalView = GlobalModalView +var BgpSummaryView = React.createClass({ + render: function() { + var self = this + + // Walk thru all objects + var BgpListView = self.props.Bgps.map(function(Bgp){ + return ( + }> + + + + + + ); + }); + + return ( +
+ + + + + + + + + { BgpListView } + +
+
+ ); + } +}); + +var BgpModalView = React.createClass({ + render() { + var obj = this.props.Bgp + return ( + +
+ + + + + + + + +
+
+ +
+
+ ); + } +}); + +module.exports.BgpSummaryView = BgpSummaryView +module.exports.BgpModalView = BgpModalView var NetworkSummaryView = React.createClass({ render: function() { var self = this diff --git a/contivModel/host.json b/contivModel/host.json new file mode 100644 index 0000000..d7fb2d0 --- /dev/null +++ b/contivModel/host.json @@ -0,0 +1,27 @@ +{ + "name": "contivModel", + "objects": [ + { + "name": "Bgp", + "type": "object", + "key": ["name"], + "properties": { + "name": { + "type": "string", + "title": "host name", + "length": 256 + }, + "AS": { + "type": "string", + "title": "AS id", + "length": 64 + }, + "neighbor":{ + "type": "string", + "title": "Bgp neighbor", + "length": 15 + } + } + }] +} +