diff --git a/client/contivModel.js b/client/contivModel.js
index 2ea3b6d..761c9d2 100644
--- a/client/contivModel.js
+++ b/client/contivModel.js
@@ -676,6 +676,71 @@ var ServiceInstanceModalView = React.createClass({
module.exports.ServiceInstanceSummaryView = ServiceInstanceSummaryView
module.exports.ServiceInstanceModalView = ServiceInstanceModalView
+var ServiceLBSummaryView = React.createClass({
+ render: function() {
+ var self = this
+
+ // Walk thru all objects
+ var serviceLBListView = self.props.serviceLBs.map(function(serviceLB){
+ return (
+ }>
+
+
+
+
+
+ );
+ });
+
+ return (
+
+
+
+
+
+
+
+
+
+ { serviceLBListView }
+
+
+
+ );
+ }
+});
+
+var ServiceLBModalView = React.createClass({
+ render() {
+ var obj = this.props.serviceLB
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+});
+
+module.exports.ServiceLBSummaryView = ServiceLBSummaryView
+module.exports.ServiceLBModalView = ServiceLBModalView
var TenantSummaryView = React.createClass({
render: function() {
var self = this
diff --git a/client/contivModelClient.go b/client/contivModelClient.go
index 73cf0a3..82ebcbf 100644
--- a/client/contivModelClient.go
+++ b/client/contivModelClient.go
@@ -238,6 +238,7 @@ type Network struct {
type NetworkLinkSets struct {
AppProfiles map[string]Link `json:"AppProfiles,omitempty"`
EndpointGroups map[string]Link `json:"EndpointGroups,omitempty"`
+ Servicelbs map[string]Link `json:"Servicelbs,omitempty"`
Services map[string]Link `json:"Services,omitempty"`
}
@@ -349,6 +350,25 @@ type ServiceInstanceLinks struct {
Service Link `json:"Service,omitempty"`
}
+type ServiceLB struct {
+ // every object has a key
+ Key string `json:"key,omitempty"`
+
+ IpAddress string `json:"ipAddress,omitempty"` // Service ip
+ Network string `json:"network,omitempty"` // Service network name
+ Ports []string `json:"ports,omitempty"`
+ Selectors []string `json:"selectors,omitempty"`
+ ServiceName string `json:"serviceName,omitempty"` // service name
+ TenantName string `json:"tenantName,omitempty"` // Tenant Name
+
+ Links ServiceLBLinks `json:"links,omitempty"`
+}
+
+type ServiceLBLinks struct {
+ Network Link `json:"Network,omitempty"`
+ Tenant Link `json:"Tenant,omitempty"`
+}
+
type Tenant struct {
// every object has a key
Key string `json:"key,omitempty"`
@@ -365,6 +385,7 @@ type TenantLinkSets struct {
EndpointGroups map[string]Link `json:"EndpointGroups,omitempty"`
Networks map[string]Link `json:"Networks,omitempty"`
Policies map[string]Link `json:"Policies,omitempty"`
+ Servicelbs map[string]Link `json:"Servicelbs,omitempty"`
VolumeProfiles map[string]Link `json:"VolumeProfiles,omitempty"`
Volumes map[string]Link `json:"Volumes,omitempty"`
}
@@ -1002,6 +1023,71 @@ func (c *ContivClient) ServiceInstanceDelete(tenantName string, appName string,
return nil
}
+// ServiceLBPost posts the serviceLB object
+func (c *ContivClient) ServiceLBPost(obj *ServiceLB) error {
+ // build key and URL
+ keyStr := obj.ServiceName + ":" + obj.TenantName
+ url := c.baseURL + "/api/serviceLBs/" + keyStr + "/"
+
+ // http post the object
+ err := httpPost(url, obj)
+ if err != nil {
+ log.Debugf("Error creating serviceLB %+v. Err: %v", obj, err)
+ return err
+ }
+
+ return nil
+}
+
+// ServiceLBList lists all serviceLB objects
+func (c *ContivClient) ServiceLBList() (*[]*ServiceLB, error) {
+ // build key and URL
+ url := c.baseURL + "/api/serviceLBs/"
+
+ // http get the object
+ var objList []*ServiceLB
+ err := httpGet(url, &objList)
+ if err != nil {
+ log.Debugf("Error getting serviceLBs. Err: %v", err)
+ return nil, err
+ }
+
+ return &objList, nil
+}
+
+// ServiceLBGet gets the serviceLB object
+func (c *ContivClient) ServiceLBGet(serviceName string, tenantName string) (*ServiceLB, error) {
+ // build key and URL
+ keyStr := serviceName + ":" + tenantName
+ url := c.baseURL + "/api/serviceLBs/" + keyStr + "/"
+
+ // http get the object
+ var obj ServiceLB
+ err := httpGet(url, &obj)
+ if err != nil {
+ log.Debugf("Error getting serviceLB %+v. Err: %v", keyStr, err)
+ return nil, err
+ }
+
+ return &obj, nil
+}
+
+// ServiceLBDelete deletes the serviceLB object
+func (c *ContivClient) ServiceLBDelete(serviceName string, tenantName string) error {
+ // build key and URL
+ keyStr := serviceName + ":" + tenantName
+ url := c.baseURL + "/api/serviceLBs/" + keyStr + "/"
+
+ // http get the object
+ err := httpDelete(url)
+ if err != nil {
+ log.Debugf("Error deleting serviceLB %s. Err: %v", keyStr, err)
+ return err
+ }
+
+ return nil
+}
+
// TenantPost posts the tenant object
func (c *ContivClient) TenantPost(obj *Tenant) error {
// build key and URL
diff --git a/client/contivModelClient.py b/client/contivModelClient.py
index 04d999d..bcd9238 100644
--- a/client/contivModelClient.py
+++ b/client/contivModelClient.py
@@ -218,6 +218,7 @@ def createNetwork(self, obj):
"encap": obj.encap,
"gateway": obj.gateway,
"networkName": obj.networkName,
+ "nwType": obj.nwType,
"pktTag": obj.pktTag,
"subnet": obj.subnet,
"tenantName": obj.tenantName,
@@ -398,6 +399,42 @@ def listServiceInstance(self):
if retData == "Error":
errorExit("list ServiceInstance failed")
+ return json.loads(retData)
+ # Create serviceLB
+ def createServiceLB(self, obj):
+ postUrl = self.baseUrl + '/api/serviceLBs/' + obj.serviceName + ":" + obj.tenantName + '/'
+
+ jdata = json.dumps({
+ "ipAddress": obj.ipAddress,
+ "network": obj.network,
+ "ports": obj.ports,
+ "selectors": obj.selectors,
+ "serviceName": obj.serviceName,
+ "tenantName": obj.tenantName,
+ })
+
+ # Post the data
+ response = httpPost(postUrl, jdata)
+
+ if response == "Error":
+ errorExit("ServiceLB create failure")
+
+ # Delete serviceLB
+ def deleteServiceLB(self, serviceName, tenantName):
+ # Delete ServiceLB
+ deleteUrl = self.baseUrl + '/api/serviceLBs/' + serviceName + ":" + tenantName + '/'
+ response = httpDelete(deleteUrl)
+
+ if response == "Error":
+ errorExit("ServiceLB create failure")
+
+ # List all serviceLB objects
+ def listServiceLB(self):
+ # Get a list of serviceLB objects
+ retDate = urllib2.urlopen(self.baseUrl + '/api/serviceLBs/')
+ if retData == "Error":
+ errorExit("list ServiceLB failed")
+
return json.loads(retData)
# Create tenant
def createTenant(self, obj):
diff --git a/contivModel.go b/contivModel.go
index a9c4308..6cf21b3 100644
--- a/contivModel.go
+++ b/contivModel.go
@@ -107,6 +107,7 @@ type Network struct {
type NetworkLinkSets struct {
AppProfiles map[string]modeldb.Link `json:"AppProfiles,omitempty"`
EndpointGroups map[string]modeldb.Link `json:"EndpointGroups,omitempty"`
+ Servicelbs map[string]modeldb.Link `json:"Servicelbs,omitempty"`
Services map[string]modeldb.Link `json:"Services,omitempty"`
}
@@ -218,6 +219,25 @@ type ServiceInstanceLinks struct {
Service modeldb.Link `json:"Service,omitempty"`
}
+type ServiceLB struct {
+ // every object has a key
+ Key string `json:"key,omitempty"`
+
+ IpAddress string `json:"ipAddress,omitempty"` // Service ip
+ Network string `json:"network,omitempty"` // Service network name
+ Ports []string `json:"ports,omitempty"`
+ Selectors []string `json:"selectors,omitempty"`
+ ServiceName string `json:"serviceName,omitempty"` // service name
+ TenantName string `json:"tenantName,omitempty"` // Tenant Name
+
+ Links ServiceLBLinks `json:"links,omitempty"`
+}
+
+type ServiceLBLinks struct {
+ Network modeldb.Link `json:"Network,omitempty"`
+ Tenant modeldb.Link `json:"Tenant,omitempty"`
+}
+
type Tenant struct {
// every object has a key
Key string `json:"key,omitempty"`
@@ -234,6 +254,7 @@ type TenantLinkSets struct {
EndpointGroups map[string]modeldb.Link `json:"EndpointGroups,omitempty"`
Networks map[string]modeldb.Link `json:"Networks,omitempty"`
Policies map[string]modeldb.Link `json:"Policies,omitempty"`
+ Servicelbs map[string]modeldb.Link `json:"Servicelbs,omitempty"`
VolumeProfiles map[string]modeldb.Link `json:"VolumeProfiles,omitempty"`
Volumes map[string]modeldb.Link `json:"Volumes,omitempty"`
}
@@ -296,6 +317,7 @@ type Collections struct {
rules map[string]*Rule
services map[string]*Service
serviceInstances map[string]*ServiceInstance
+ serviceLBs map[string]*ServiceLB
tenants map[string]*Tenant
volumes map[string]*Volume
volumeProfiles map[string]*VolumeProfile
@@ -357,6 +379,12 @@ type ServiceInstanceCallbacks interface {
ServiceInstanceDelete(serviceInstance *ServiceInstance) error
}
+type ServiceLBCallbacks interface {
+ ServiceLBCreate(serviceLB *ServiceLB) error
+ ServiceLBUpdate(serviceLB, params *ServiceLB) error
+ ServiceLBDelete(serviceLB *ServiceLB) error
+}
+
type TenantCallbacks interface {
TenantCreate(tenant *Tenant) error
TenantUpdate(tenant, params *Tenant) error
@@ -385,6 +413,7 @@ type CallbackHandlers struct {
RuleCb RuleCallbacks
ServiceCb ServiceCallbacks
ServiceInstanceCb ServiceInstanceCallbacks
+ ServiceLBCb ServiceLBCallbacks
TenantCb TenantCallbacks
VolumeCb VolumeCallbacks
VolumeProfileCb VolumeProfileCallbacks
@@ -402,6 +431,7 @@ func Init() {
collections.rules = make(map[string]*Rule)
collections.services = make(map[string]*Service)
collections.serviceInstances = make(map[string]*ServiceInstance)
+ collections.serviceLBs = make(map[string]*ServiceLB)
collections.tenants = make(map[string]*Tenant)
collections.volumes = make(map[string]*Volume)
collections.volumeProfiles = make(map[string]*VolumeProfile)
@@ -415,6 +445,7 @@ func Init() {
restoreRule()
restoreService()
restoreServiceInstance()
+ restoreServiceLB()
restoreTenant()
restoreVolume()
restoreVolumeProfile()
@@ -457,6 +488,10 @@ func RegisterServiceInstanceCallbacks(handler ServiceInstanceCallbacks) {
objCallbackHandler.ServiceInstanceCb = handler
}
+func RegisterServiceLBCallbacks(handler ServiceLBCallbacks) {
+ objCallbackHandler.ServiceLBCb = handler
+}
+
func RegisterTenantCallbacks(handler TenantCallbacks) {
objCallbackHandler.TenantCb = handler
}
@@ -598,6 +633,16 @@ func AddRoutes(router *mux.Router) {
router.Path(route).Methods("PUT").HandlerFunc(makeHttpHandler(httpCreateServiceInstance))
router.Path(route).Methods("DELETE").HandlerFunc(makeHttpHandler(httpDeleteServiceInstance))
+ // Register serviceLB
+ route = "/api/serviceLBs/{key}/"
+ listRoute = "/api/serviceLBs/"
+ log.Infof("Registering %s", route)
+ router.Path(listRoute).Methods("GET").HandlerFunc(makeHttpHandler(httpListServiceLBs))
+ router.Path(route).Methods("GET").HandlerFunc(makeHttpHandler(httpGetServiceLB))
+ router.Path(route).Methods("POST").HandlerFunc(makeHttpHandler(httpCreateServiceLB))
+ router.Path(route).Methods("PUT").HandlerFunc(makeHttpHandler(httpCreateServiceLB))
+ router.Path(route).Methods("DELETE").HandlerFunc(makeHttpHandler(httpDeleteServiceLB))
+
// Register tenant
route = "/api/tenants/{key}/"
listRoute = "/api/tenants/"
@@ -2910,6 +2955,261 @@ func ValidateServiceInstance(obj *ServiceInstance) error {
return nil
}
+// LIST REST call
+func httpListServiceLBs(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) {
+ log.Debugf("Received httpListServiceLBs: %+v", vars)
+
+ list := make([]*ServiceLB, 0)
+ for _, obj := range collections.serviceLBs {
+ list = append(list, obj)
+ }
+
+ // Return the list
+ return list, nil
+}
+
+// GET REST call
+func httpGetServiceLB(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) {
+ log.Debugf("Received httpGetServiceLB: %+v", vars)
+
+ key := vars["key"]
+
+ obj := collections.serviceLBs[key]
+ if obj == nil {
+ log.Errorf("serviceLB %s not found", key)
+ return nil, errors.New("serviceLB not found")
+ }
+
+ // Return the obj
+ return obj, nil
+}
+
+// CREATE REST call
+func httpCreateServiceLB(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) {
+ log.Debugf("Received httpGetServiceLB: %+v", vars)
+
+ var obj ServiceLB
+ key := vars["key"]
+
+ // Get object from the request
+ err := json.NewDecoder(r.Body).Decode(&obj)
+ if err != nil {
+ log.Errorf("Error decoding serviceLB create request. Err %v", err)
+ return nil, err
+ }
+
+ // set the key
+ obj.Key = key
+
+ // Create the object
+ err = CreateServiceLB(&obj)
+ if err != nil {
+ log.Errorf("CreateServiceLB error for: %+v. Err: %v", obj, err)
+ return nil, err
+ }
+
+ // Return the obj
+ return obj, nil
+}
+
+// DELETE rest call
+func httpDeleteServiceLB(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) {
+ log.Debugf("Received httpDeleteServiceLB: %+v", vars)
+
+ key := vars["key"]
+
+ // Delete the object
+ err := DeleteServiceLB(key)
+ if err != nil {
+ log.Errorf("DeleteServiceLB error for: %s. Err: %v", key, err)
+ return nil, err
+ }
+
+ // Return the obj
+ return key, nil
+}
+
+// Create a serviceLB object
+func CreateServiceLB(obj *ServiceLB) error {
+ // Validate parameters
+ err := ValidateServiceLB(obj)
+ if err != nil {
+ log.Errorf("ValidateServiceLB retruned error for: %+v. Err: %v", obj, err)
+ return err
+ }
+
+ // Check if we handle this object
+ if objCallbackHandler.ServiceLBCb == nil {
+ log.Errorf("No callback registered for serviceLB object")
+ return errors.New("Invalid object type")
+ }
+
+ saveObj := obj
+
+ // Check if object already exists
+ if collections.serviceLBs[obj.Key] != nil {
+ // Perform Update callback
+ err = objCallbackHandler.ServiceLBCb.ServiceLBUpdate(collections.serviceLBs[obj.Key], obj)
+ if err != nil {
+ log.Errorf("ServiceLBUpdate retruned error for: %+v. Err: %v", obj, err)
+ return err
+ }
+
+ // save the original object after update
+ saveObj = collections.serviceLBs[obj.Key]
+ } else {
+ // save it in cache
+ collections.serviceLBs[obj.Key] = obj
+
+ // Perform Create callback
+ err = objCallbackHandler.ServiceLBCb.ServiceLBCreate(obj)
+ if err != nil {
+ log.Errorf("ServiceLBCreate retruned error for: %+v. Err: %v", obj, err)
+ delete(collections.serviceLBs, obj.Key)
+ return err
+ }
+ }
+
+ // Write it to modeldb
+ err = saveObj.Write()
+ if err != nil {
+ log.Errorf("Error saving serviceLB %s to db. Err: %v", saveObj.Key, err)
+ return err
+ }
+
+ return nil
+}
+
+// Return a pointer to serviceLB from collection
+func FindServiceLB(key string) *ServiceLB {
+ obj := collections.serviceLBs[key]
+ if obj == nil {
+ return nil
+ }
+
+ return obj
+}
+
+// Delete a serviceLB object
+func DeleteServiceLB(key string) error {
+ obj := collections.serviceLBs[key]
+ if obj == nil {
+ log.Errorf("serviceLB %s not found", key)
+ return errors.New("serviceLB not found")
+ }
+
+ // Check if we handle this object
+ if objCallbackHandler.ServiceLBCb == nil {
+ log.Errorf("No callback registered for serviceLB object")
+ return errors.New("Invalid object type")
+ }
+
+ // Perform callback
+ err := objCallbackHandler.ServiceLBCb.ServiceLBDelete(obj)
+ if err != nil {
+ log.Errorf("ServiceLBDelete retruned error for: %+v. Err: %v", obj, err)
+ return err
+ }
+
+ // delete it from modeldb
+ err = obj.Delete()
+ if err != nil {
+ log.Errorf("Error deleting serviceLB %s. Err: %v", obj.Key, err)
+ }
+
+ // delete it from cache
+ delete(collections.serviceLBs, key)
+
+ return nil
+}
+
+func (self *ServiceLB) GetType() string {
+ return "serviceLB"
+}
+
+func (self *ServiceLB) GetKey() string {
+ return self.Key
+}
+
+func (self *ServiceLB) Read() error {
+ if self.Key == "" {
+ log.Errorf("Empty key while trying to read serviceLB object")
+ return errors.New("Empty key")
+ }
+
+ return modeldb.ReadObj("serviceLB", self.Key, self)
+}
+
+func (self *ServiceLB) Write() error {
+ if self.Key == "" {
+ log.Errorf("Empty key while trying to Write serviceLB object")
+ return errors.New("Empty key")
+ }
+
+ return modeldb.WriteObj("serviceLB", self.Key, self)
+}
+
+func (self *ServiceLB) Delete() error {
+ if self.Key == "" {
+ log.Errorf("Empty key while trying to Delete serviceLB object")
+ return errors.New("Empty key")
+ }
+
+ return modeldb.DeleteObj("serviceLB", self.Key)
+}
+
+func restoreServiceLB() error {
+ strList, err := modeldb.ReadAllObj("serviceLB")
+ if err != nil {
+ log.Errorf("Error reading serviceLB list. Err: %v", err)
+ }
+
+ for _, objStr := range strList {
+ // Parse the json model
+ var serviceLB ServiceLB
+ err = json.Unmarshal([]byte(objStr), &serviceLB)
+ if err != nil {
+ log.Errorf("Error parsing object %s, Err %v", objStr, err)
+ return err
+ }
+
+ // add it to the collection
+ collections.serviceLBs[serviceLB.Key] = &serviceLB
+ }
+
+ return nil
+}
+
+// Validate a serviceLB object
+func ValidateServiceLB(obj *ServiceLB) error {
+ // Validate key is correct
+ keyStr := obj.ServiceName + ":" + obj.TenantName
+ if obj.Key != keyStr {
+ log.Errorf("Expecting ServiceLB Key: %s. Got: %s", keyStr, obj.Key)
+ return errors.New("Invalid Key")
+ }
+
+ // Validate each field
+
+ if len(obj.IpAddress) > 15 {
+ return errors.New("ipAddress string too long")
+ }
+
+ if len(obj.Network) > 64 {
+ return errors.New("network string too long")
+ }
+
+ if len(obj.ServiceName) > 256 {
+ return errors.New("serviceName string too long")
+ }
+
+ if len(obj.TenantName) > 64 {
+ return errors.New("tenantName string too long")
+ }
+
+ return nil
+}
+
// LIST REST call
func httpListTenants(w http.ResponseWriter, r *http.Request, vars map[string]string) (interface{}, error) {
log.Debugf("Received httpListTenants: %+v", vars)
diff --git a/network.json b/network.json
index 2a062e2..e400f45 100644
--- a/network.json
+++ b/network.json
@@ -57,7 +57,10 @@
},
"endpointGroups": {
"ref": "endpointGroup"
- }
+ },
+ "servicelbs":{
+ "ref": "servicelb"
+ }
},
"links": {
"tenant": {
diff --git a/servicelb.json b/servicelb.json
new file mode 100755
index 0000000..29fc874
--- /dev/null
+++ b/servicelb.json
@@ -0,0 +1,52 @@
+{
+ "name": "contivModel",
+ "objects": [
+ {
+ "name": "serviceLB",
+ "type": "object",
+ "key": ["serviceName","tenantName"],
+ "properties": {
+ "serviceName": {
+ "type": "string",
+ "title": "service name",
+ "length": 256
+ },
+ "tenantName": {
+ "type": "string",
+ "title": "Tenant Name",
+ "length": 64
+ },
+
+ "network": {
+ "type": "string",
+ "title": "Service network name",
+ "length": 64
+ },
+ "ipAddress":{
+ "type":"string",
+ "title":"Service ip",
+ "length": 15
+ },
+ "selectors": {
+ "type": "array",
+ "title": "labels key value pair",
+ "length": 512,
+ "items" :"string"
+ },
+ "ports":{
+ "type":"array",
+ "title":"service provider port",
+ "length": 32,
+ "items" : "string"
+ }
+ },
+ "links": {
+ "tenant": {
+ "ref": "tenant"
+ },
+ "network": {
+ "ref": "network"
+ }
+ }
+ }]
+}
diff --git a/tenant.json b/tenant.json
index bdc21fe..4aaae38 100644
--- a/tenant.json
+++ b/tenant.json
@@ -35,7 +35,10 @@
},
"volumeProfiles": {
"ref": "volumeProfile"
- }
+ },
+ "servicelbs":{
+ "ref": "servicelb"
+ }
}
}
]