New changes in scc to support multi-hub 72/4572/3
authorRuoyu Ying <ruoyu.ying@intel.com>
Tue, 21 Dec 2021 08:49:29 +0000 (03:49 -0500)
committerRuoyu Ying <ruoyu.ying@intel.com>
Wed, 22 Dec 2021 10:00:54 +0000 (05:00 -0500)
Change-Id: I3479dd905eddbf5ff0d0b688e18ea9c8ada52b48
Signed-off-by: Ruoyu Ying <ruoyu.ying@intel.com>
21 files changed:
central-controller/src/scc/api/api.go
central-controller/src/scc/pkg/manager/connection_manager.go
central-controller/src/scc/pkg/manager/constants.go
central-controller/src/scc/pkg/manager/device_objectmanager.go
central-controller/src/scc/pkg/manager/hub_objectmanager.go
central-controller/src/scc/pkg/manager/hubconnection_objectmanager.go
central-controller/src/scc/pkg/manager/hubdevice_objectmanager.go
central-controller/src/scc/pkg/manager/managerset.go
central-controller/src/scc/pkg/manager/overlay_objectmanager.go
central-controller/src/scc/pkg/manager/resource_objectmanager.go [new file with mode: 0644]
central-controller/src/scc/pkg/manager/resutils.go
central-controller/src/scc/pkg/module/connectionobject.go
central-controller/src/scc/pkg/module/deviceobject.go
central-controller/src/scc/pkg/module/hubdeviceobject.go
central-controller/src/scc/pkg/module/hubobject.go
central-controller/src/scc/pkg/module/resourceobject.go [new file with mode: 0644]
central-controller/src/scc/pkg/resource/empty_resource.go
central-controller/src/scc/pkg/resource/firewall_nat_resource.go [new file with mode: 0644]
central-controller/src/scc/pkg/resource/ipsec_resource.go
central-controller/src/scc/pkg/resource/resourcebuilder.go
central-controller/src/scc/pkg/resource/route_resource.go [new file with mode: 0644]

index 648669f..b7be3e8 100644 (file)
@@ -167,6 +167,9 @@ func NewRouter(
        mgrset.Cert = certificateObjectClient.(*manager.CertificateObjectManager)
        createHandlerMapping(certificateObjectClient, olRouter, manager.CertCollection, manager.CertResource)
 
+       // create resource object manager
+       mgrset.Resource = manager.NewResourceObjectManager()
+
        // Add depedency
        overlayObjectClient.AddOwnResManager(proposalObjectClient)
        overlayObjectClient.AddOwnResManager(hubObjectClient)
index cfccc4b..ea38552 100644 (file)
@@ -56,38 +56,17 @@ func (c *ConnectionManager) GetStoreMeta() string {
        return c.tagMeta
 }
 
-func (c *ConnectionManager) Deploy(overlay string, cm module.ConnectionObject) error {
-       resutil := NewResUtil()
-
-       // add resource for End1
-       co1, _ := module.GetObjectBuilder().ToObject(cm.Info.End1.ConnObject)
-       for _, r_str := range cm.Info.End1.Resources {
-               r, _ := resource.GetResourceBuilder().ToObject(r_str)
-               resutil.AddResource(co1, "create", r)
-       }
-       for _, r_str := range cm.Info.End1.ReservedRes {
-               r, _ := resource.GetResourceBuilder().ToObject(r_str)
-               resutil.AddResource(co1, "create", r)
-       }
-
-       // add resource for End2
-       co2, _ := module.GetObjectBuilder().ToObject(cm.Info.End2.ConnObject)
-       for _, r_str := range cm.Info.End2.Resources {
-               r, _ := resource.GetResourceBuilder().ToObject(r_str)
-               resutil.AddResource(co2, "create", r)
-       }
-       for _, r_str := range cm.Info.End2.ReservedRes {
-               r, _ := resource.GetResourceBuilder().ToObject(r_str)
-               resutil.AddResource(co2, "create", r)
+func (c *ConnectionManager) Deploy(overlay string, cm module.ConnectionObject, resutil *ResUtil) error {
+       // add resource to cm
+       rm := resutil.GetResources()
+       for device, res := range rm {
+               for _, resource := range res.Resources {
+                       cm.Info.AddResource(device, resource.Resource.GetName(), resource.Resource.GetType())
+               }
        }
 
        // Deploy resources
-       cid, err := resutil.Deploy(cm.Metadata.Name, "YAML")
-       if cm.Info.ContextId == "" {
-               cm.Info.ContextId = cid
-       } else {
-               cm.Info.ContextId = cm.Info.ContextId + "," + cid
-       }
+       err := resutil.Deploy(overlay, cm.Metadata.Name, "YAML")
 
        if err != nil {
                log.Println(err)
@@ -97,6 +76,7 @@ func (c *ConnectionManager) Deploy(overlay string, cm module.ConnectionObject) e
                cm.Info.State = module.StateEnum.Deployed
        }
 
+       log.Println(cm.Info.End1.IP)
        // Save to DB
        _, err = c.UpdateObject(overlay, cm)
 
@@ -105,28 +85,14 @@ func (c *ConnectionManager) Deploy(overlay string, cm module.ConnectionObject) e
 
 func (c *ConnectionManager) Undeploy(overlay string, cm module.ConnectionObject) error {
        resutil := NewResUtil()
-
-       // add resource for End1 (reservedRes will be kept)
-       co1, _ := module.GetObjectBuilder().ToObject(cm.Info.End1.ConnObject)
-       for _, r_str := range cm.Info.End1.Resources {
-               r, _ := resource.GetResourceBuilder().ToObject(r_str)
-               resutil.AddResource(co1, "create", r)
-       }
-
-       // add resource for End2 (reservedRes will be kept)
-       co2, _ := module.GetObjectBuilder().ToObject(cm.Info.End2.ConnObject)
-       for _, r_str := range cm.Info.End2.Resources {
-               r, _ := resource.GetResourceBuilder().ToObject(r_str)
-               resutil.AddResource(co2, "create", r)
+       // fill resutil
+       for _, res := range cm.Info.Resources {
+               co, _ := module.GetObjectBuilder().ToObject(res.ConnObject)
+               resutil.AddResource(co, "delete", &resource.EmptyResource{res.Name, res.Type})
        }
 
        // Undeploy resources
-       cid, err := resutil.Undeploy(cm.Metadata.Name, "YAML")
-       if cm.Info.ContextId == "" {
-               cm.Info.ContextId = cid
-       } else {
-               cm.Info.ContextId = cm.Info.ContextId + "," + cid
-       }
+       err := resutil.Undeploy(overlay)
 
        if err != nil {
                log.Println(err)
index 230fc72..511372e 100644 (file)
 package manager
 
 const (
-       NameSpaceName        = "sdewan-system"
-       RootIssuerName       = "sdewan-controller"
-       RootCAIssuerName     = "sdewan-controller-ca"
-       RootCertName         = "sdewan-controller"
-       SCCCertName          = "sdewan-controller-base"
-       StoreName            = "centralcontroller"
-       OverlayCollection    = "overlays"
-       OverlayResource      = "overlay-name"
-       ProposalCollection   = "proposals"
-       ProposalResource     = "proposal-name"
-       HubCollection        = "hubs"
-       HubResource          = "hub-name"
-       ConnectionCollection = "connections"
-       ConnectionResource   = "connection-name"
-       CNFCollection        = "cnfs"
-       CNFResource          = "cnf-name"
-       DeviceCollection     = "devices"
-       DeviceResource       = "device-name"
-       IPRangeCollection    = "ipranges"
-       IPRangeResource      = "iprange-name"
-       CertCollection       = "certificates"
-       CertResource         = "certificate-name"
+        NameSpaceName               = "sdewan-system"
+        RootIssuerName              = "sdewan-controller"
+        RootCAIssuerName            = "sdewan-controller-ca"
+        RootCertName                = "sdewan-controller"
+        SCCCertName                 = "sdewan-controller-base"
+        StoreName                   = "centralcontroller"
+        OverlayCollection           = "overlays"
+        OverlayResource             = "overlay-name"
+        ProposalCollection          = "proposals"
+        ProposalResource            = "proposal-name"
+        HubCollection               = "hubs"
+        HubResource                 = "hub-name"
+        ConnectionCollection        = "connections"
+        ConnectionResource          = "connection-name"
+        CNFCollection               = "cnfs"
+        CNFResource                 = "cnf-name"
+        DeviceCollection            = "devices"
+        DeviceResource              = "device-name"
+        IPRangeCollection           = "ipranges"
+        IPRangeResource             = "iprange-name"
+        CertCollection              = "certificates"
+        CertResource                = "certificate-name"
+        Resource                    = "resource"
+        Resource_Status_NotDeployed = "NotDeployed"
+        Resource_Status_Deployed    = "Deployed"
 )
index 4bf601a..547beea 100644 (file)
@@ -190,7 +190,7 @@ func (c *DeviceObjectManager) PreProcessing(m map[string]string, t module.Contro
                scc_conn := resource.Connection{
                        Name:           DEFAULT_CONN + format_resource_name(to.Metadata.Name, ""),
                        ConnectionType: CONN_TYPE,
-                       Mode:           MODE,
+                       Mode:           START_MODE,
                        Mark:           DEFAULT_MARK,
                        RemoteSourceIp: oip,
                        LocalUpDown:    DEFAULT_UPDOWN,
@@ -222,7 +222,7 @@ func (c *DeviceObjectManager) PreProcessing(m map[string]string, t module.Contro
                        resutil.AddResource(&scc, "create", proposalresource[i])
                }
 
-               resutil.Deploy("localto"+to.Metadata.Name, "YAML")
+               resutil.Deploy(overlay_name, "localto"+to.Metadata.Name, "YAML")
 
                //Reserve ipsec resource to device object
                res_str, err := resource.GetResourceBuilder().ToString(&scc_ipsec_resource)
@@ -300,7 +300,7 @@ func (c *DeviceObjectManager) DeleteObject(m map[string]string) error {
        overlay_manager := GetManagerset().Overlay
        ipr_manager := GetManagerset().ProviderIPRange
 
-       device_name := m[DeviceResource]
+       overlay_name := m[OverlayResource]
 
        to := t.(*module.DeviceObject)
 
@@ -318,7 +318,7 @@ func (c *DeviceObjectManager) DeleteObject(m map[string]string) error {
                r_str := to.Status.Data["scc_ipsec_resource"]
                r, _ := resource.GetResourceBuilder().ToObject(r_str)
                resutils.AddResource(&scc, "create", r)
-               resutils.Undeploy("localto"+device_name, "YAML")
+               resutils.Undeploy(overlay_name)
        }
 
        log.Println("Delete device...")
@@ -375,6 +375,21 @@ func (c *DeviceObjectManager) PostRegister(m map[string]string, t module.Control
 
        } else {
                to.Status.Data[RegStatus] = "success"
+                err := GetDBUtils().RegisterDevice(to.Metadata.Name, to.Specification.KubeConfig)
+                if err != nil {
+                        log.Println(err)
+                        return err
+                }
+
+                overlay := GetManagerset().Overlay
+                overlay_name := m[OverlayResource]
+
+                log.Println("Create Certificate: " + to.GetCertName())
+                _, _, err = overlay.CreateCertificate(overlay_name, to.GetCertName())
+                if err != nil {
+                        log.Println(err)
+                        return err
+                }
        }
 
        if to.Status.Data[RegStatus] == "success" {
@@ -389,7 +404,7 @@ func (c *DeviceObjectManager) PostRegister(m map[string]string, t module.Control
                for i := 0; i < len(devices); i++ {
                        dev := devices[i].(*module.DeviceObject)
                        if to.Status.Mode == 1 || dev.Status.Mode == 1 {
-                               err = overlay_manager.SetupConnection(m, to, dev, DEVICETODEVICE, NameSpaceName)
+                               err = overlay_manager.SetupConnection(m, to, dev, DEVICETODEVICE, NameSpaceName, false)
                                if err != nil {
                                        return err
                                }
index db7e172..bdd66a6 100644 (file)
@@ -101,7 +101,6 @@ func (c *HubObjectManager) ParseObject(r io.Reader) (module.ControllerObject, er
 
        // initial Status
        v.Status.Data = make(map[string]string)
-       v.Status.ProxyPort = make(map[string]string)
        return &v, err
 }
 
@@ -153,7 +152,7 @@ func (c *HubObjectManager) CreateObject(m map[string]string, t module.Controller
        //Maybe because of cert not ready or other reasons.
        if len(hubs) > 0 && err == nil {
                for i := 0; i < len(hubs); i++ {
-                       err := overlay.SetupConnection(m, t, hubs[i], HUBTOHUB, NameSpaceName)
+                       err := overlay.SetupConnection(m, t, hubs[i], HUBTOHUB, NameSpaceName, false)
                        if err != nil {
                                log.Println("Setup connection with " + hubs[i].(*module.HubObject).Metadata.Name + " failed.")
                        }
index e858d7b..13569fc 100644 (file)
@@ -124,3 +124,26 @@ func (c *HubConnObjectManager) UpdateObject(m map[string]string, t module.Contro
 func (c *HubConnObjectManager) DeleteObject(m map[string]string) error {
        return pkgerrors.New("Not implemented")
 }
+
+func (c *HubConnObjectManager) GetConnectedDevices(overlay_name string, hub_name string) ([]string, error) {
+       m := make(map[string]string)
+       m[OverlayResource] = overlay_name
+       m[HubResource] = hub_name
+
+       // get all connections
+       cs, err := c.GetObjects(m)
+       if err != nil {
+               return []string{}, err
+       }
+
+       var device_names []string
+       for _, c := range cs {
+               co := c.(*module.ConnectionObject)
+               // get peer end's type and name
+               t, n, ip := co.GetPeer("Hub", hub_name)
+               if t == "Device" {
+                       device_names = append(device_names, n + ".." + ip)
+               }
+       }
+       return device_names, nil
+}
index 821b6be..47b45b2 100644 (file)
@@ -91,6 +91,7 @@ func (c *HubDeviceObjectManager) CreateObject(m map[string]string, t module.Cont
        to := t.(*module.HubDeviceObject)
        device_name := to.Specification.Device
        m[DeviceResource] = device_name
+       is_delegated_connection := to.Specification.IsDelegateHub
 
        hub_manager := GetManagerset().Hub
        dev_manager := GetManagerset().Device
@@ -113,6 +114,10 @@ func (c *HubDeviceObjectManager) CreateObject(m map[string]string, t module.Cont
                return c.CreateEmptyObject(), pkgerrors.Wrap(err, "Device "+device_name+" registration is not ready")
        }
 
+       if device.Status.DelegatedHub != "" {
+               is_delegated_connection = false
+       }
+
        _, err = conn_manager.GetObject(overlay_name,
                module.CreateEndName(hub.GetType(), hub.GetMetadata().Name),
                module.CreateEndName(dev.GetType(), dev.GetMetadata().Name))
@@ -120,11 +125,20 @@ func (c *HubDeviceObjectManager) CreateObject(m map[string]string, t module.Cont
                return c.CreateEmptyObject(), pkgerrors.New("The connection between Hub " + hub_name + " and Device " + device_name + " is already created")
        }
 
-       err = overlay_namager.SetupConnection(m, hub, dev, HUBTODEVICE, NameSpaceName)
+       err = overlay_namager.SetupConnection(m, hub, dev, HUBTODEVICE, NameSpaceName, is_delegated_connection)
        if err != nil {
                return c.CreateEmptyObject(), pkgerrors.Wrap(err, "Fail to setup connection between "+hub_name+" and "+device_name)
        }
 
+       if is_delegated_connection {
+               hub_obj := hub.(*module.HubObject)
+               hub_obj.Status.DelegateDevices = append(hub_obj.Status.DelegateDevices, device_name)
+               hub_manager.UpdateObject(m, hub_obj)
+
+               device.Status.DelegatedHub = hub_name
+               dev_manager.UpdateObject(m, device)
+        }
+
        return c.CreateEmptyObject(), nil
 }
 
@@ -161,6 +175,19 @@ func (c *HubDeviceObjectManager) DeleteObject(m map[string]string) error {
                return pkgerrors.Wrap(err, "Device "+device_name+" is not defined")
        }
 
+       dev_obj := dev.(*module.DeviceObject)
+       hub_obj := hub.(*module.HubObject)
+
+       if dev_obj.Status.DelegatedHub == hub_obj.Metadata.Name {
+               dev_obj.Status.DelegatedHub = ""
+               for i, item := range hub_obj.Status.DelegateDevices {
+                       if item == dev_obj.Metadata.Name {
+                               hub_obj.Status.DelegateDevices = append(hub_obj.Status.DelegateDevices[:i], hub_obj.Status.DelegateDevices[i+1:]...)
+                               break
+                       }
+               }
+       }
+
        conn, err := conn_manager.GetObject(overlay_name,
                module.CreateEndName(hub.GetType(), hub.GetMetadata().Name),
                module.CreateEndName(dev.GetType(), dev.GetMetadata().Name))
index afbbb6e..fb0c09a 100644 (file)
@@ -29,6 +29,7 @@ type Managerset struct {
        ProviderIPRange *IPRangeObjectManager
        IPRange         *IPRangeObjectManager
        Cert            *CertificateObjectManager
+       Resource        *ResourceObjectManager
 }
 
 var mgrset = Managerset{}
index 22e8c8b..41b1073 100644 (file)
@@ -28,26 +28,30 @@ import (
        "strings"
 )
 
-const DEFAULT_MARK = "30"
-const VTI_MODE = "VTI-based"
-const POLICY_MODE = "policy-based"
-const PUBKEY_AUTH = "pubkey"
-const FORCECRYPTOPROPOSAL = "0"
-const DEFAULT_CONN = "Conn"
-const DEFAULT_UPDOWN = "/etc/updown"
-const IPTABLES_UPDOWN = "/usr/lib/ipsec/_updown iptables"
-const OIP_UPDOWN = "/etc/updown_oip"
-const CONN_TYPE = "tunnel"
-const MODE = "start"
-const OVERLAYIP = "overlayip"
-const HUBTOHUB = "hub-to-hub"
-const HUBTODEVICE = "hub-to-device"
-const DEVICETODEVICE = "device-to-device"
-const BYCONFIG = "%config"
-const ANY = "%any"
-const BASE_PROTOCOL = "TCP"
-const DEFAULT_K8S_API_SERVER_PORT = "6443"
-const ACCEPT = "ACCEPT"
+const (
+ DEFAULT_MARK = "30"
+ VTI_MODE = "VTI-based"
+ POLICY_MODE = "policy-based"
+ PUBKEY_AUTH = "pubkey"
+ FORCECRYPTOPROPOSAL = "0"
+ DEFAULT_CONN = "Conn"
+ DEFAULT_UPDOWN = "/etc/updown"
+ IPTABLES_UPDOWN = "/usr/lib/ipsec/_updown iptables"
+ OIP_UPDOWN = "/etc/updown_oip"
+ CONN_TYPE = "tunnel"
+ START_MODE = "start"
+ ADD_MODE = "add"
+ OVERLAYIP = "overlayip"
+ HUBTOHUB = "hub-to-hub"
+ HUBTODEVICE = "hub-to-device"
+ DEVICETODEVICE = "device-to-device"
+ BYCONFIG = "%config"
+ ANY = "%any"
+ BASE_PROTOCOL = "TCP"
+ DEFAULT_K8S_API_SERVER_PORT = "6443"
+ ACCEPT = "ACCEPT"
+ WILDCARD_SUBNET="0.0.0.0"
+)
 
 type OverlayObjectKey struct {
        OverlayName string `json:"overlay-name"`
@@ -246,8 +250,14 @@ func (c *OverlayObjectManager) GetCertificate(oname string) (string, string, err
 
 //Set up Connection between objects
 //Passing the original map resource, the two objects, connection type("hub-to-hub", "hub-to-device", "device-to-device") and namespace name.
-func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.ControllerObject, m2 module.ControllerObject, conntype string, namespace string) error {
+func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.ControllerObject, m2 module.ControllerObject, conntype string, namespace string, is_delegated bool) error {
        //Get all proposals available in the overlay
+       resutil := NewResUtil()
+       hubConn := GetManagerset().HubConn
+       hub_manager := GetManagerset().Hub
+       dev_manager := GetManagerset().Device
+       overlay_name := m[OverlayResource]
+
        proposal := GetManagerset().Proposal
        proposals, err := proposal.GetObjects(m)
        if len(proposals) == 0 || err != nil {
@@ -255,12 +265,16 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                return pkgerrors.New("Error in getting proposals")
        }
        var all_proposals []string
-       var proposalresources []*resource.ProposalResource
+//     var proposalresources []*resource.ProposalResource
        for i := 0; i < len(proposals); i++ {
                proposal_obj := proposals[i].(*module.ProposalObject)
                all_proposals = append(all_proposals, proposal_obj.Metadata.Name)
                pr := proposal_obj.ToResource()
-               proposalresources = append(proposalresources, pr)
+//             proposalresources = append(proposalresources, pr)
+
+               // Add proposal resources
+               resutil.AddResource(m1, "create", pr)
+               resutil.AddResource(m2, "create", pr)
        }
 
        device_mgr := GetManagerset().Device
@@ -293,11 +307,23 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                }
 
                //IpsecResources
-               conn := resource.Connection{
+               conn1 := resource.Connection{
                        Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, obj2.Metadata.Name),
                        ConnectionType: CONN_TYPE,
-                       Mode:           MODE,
+                       Mode:           ADD_MODE,
                        Mark:           DEFAULT_MARK,
+                       LocalSubnet:    WILDCARD_SUBNET+"/0",
+                       RemoteSubnet:   WILDCARD_SUBNET+"/0",
+                       LocalUpDown:    DEFAULT_UPDOWN,
+                       CryptoProposal: all_proposals,
+               }
+               conn2 := resource.Connection{
+                       Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, obj2.Metadata.Name),
+                       Mark:           DEFAULT_MARK,
+                       Mode:           START_MODE,
+                       ConnectionType: CONN_TYPE,
+                       LocalSubnet:    WILDCARD_SUBNET+"/0",
+                       RemoteSubnet:   WILDCARD_SUBNET+"/0",
                        LocalUpDown:    DEFAULT_UPDOWN,
                        CryptoProposal: all_proposals,
                }
@@ -313,7 +339,7 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                        RemoteIdentifier:     "CN=" + obj2.GetCertName(),
                        CryptoProposal:       all_proposals,
                        ForceCryptoProposal:  FORCECRYPTOPROPOSAL,
-                       Connections:          conn,
+                       Connections:          conn1,
                }
                obj2_ipsec_resource = resource.IpsecResource{
                        Name:                 format_resource_name(obj2.Metadata.Name, obj1.Metadata.Name),
@@ -327,15 +353,31 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                        RemoteIdentifier:     "CN=" + obj1.GetCertName(),
                        CryptoProposal:       all_proposals,
                        ForceCryptoProposal:  FORCECRYPTOPROPOSAL,
-                       Connections:          conn,
+                       Connections:          conn2,
+               }
+
+               // for each edge connect to hub2(obj2), add Route in hub1(obj1)
+               // Todo: handle the error the route rule may fail if the vti interface is not exist 
+               dev_names, _ := hubConn.GetConnectedDevices(overlay_name, obj2.Metadata.Name)
+               for _, dev_name := range dev_names {
+                       log.Println(dev_name)
+                       strs := strings.SplitN(dev_name, "..", 2)
+                       if len(strs) == 2 {
+                               log.Println("Route Rule in " + obj1.Metadata.Name + " : " + strs[1] + " via " + obj2.Metadata.Name)
+                               resutil.AddResource(m1, "create", &resource.RouteResource {
+                                       Name: strs[1] + "-" + obj2_ip,
+                                       Destination: strs[1],
+                                       Device: "vti_" + obj2_ip, // Todo: use the right ifname
+                                       Table: "default", // Todo: need check
+                               })
+                       }
                }
-               // Todo: Hub-to-device connection
        case HUBTODEVICE:
                obj1 := m1.(*module.HubObject)
                obj2 := m2.(*module.DeviceObject)
 
-               obj1_ip := obj1.Status.Ip
-               obj2_ip, _ := device_mgr.AllocateIP(m, m2, module.CreateEndName(obj1.GetType(), obj1.Metadata.Name))
+               obj1_ip = obj1.Status.Ip
+               obj2_ip, _ = device_mgr.AllocateIP(m, m2, module.CreateEndName(obj1.GetType(), obj1.Metadata.Name))
 
                //Keypair
                obj1_crt, obj1_key, err := GetHubCertificate(obj1.GetCertName(), namespace)
@@ -346,10 +388,11 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                obj1_conn := resource.Connection{
                        Name:           DEFAULT_CONN + format_resource_name(obj2.Metadata.Name, ""),
                        ConnectionType: CONN_TYPE,
-                       Mode:           MODE,
+                       Mode:           START_MODE,
                        Mark:           DEFAULT_MARK,
                        RemoteSourceIp: obj2_ip,
                        LocalUpDown:    DEFAULT_UPDOWN,
+                       LocalSubnet:    WILDCARD_SUBNET+"/0",
                        CryptoProposal: all_proposals,
                }
 
@@ -376,10 +419,11 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                //IpsecResources
                obj2_conn := resource.Connection{
                        Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, ""),
-                       Mode:           MODE,
-                       LocalUpDown:    IPTABLES_UPDOWN,
+                       Mode:           START_MODE,
+                       LocalUpDown:    OIP_UPDOWN,
                        ConnectionType: CONN_TYPE,
                        LocalSourceIp:  BYCONFIG,
+                       RemoteSubnet:   WILDCARD_SUBNET+"/0",
                        CryptoProposal: all_proposals,
                }
                obj2_ipsec_resource = resource.IpsecResource{
@@ -397,13 +441,98 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                        Connections:          obj2_conn,
                }
 
-               //Todo: Device-to-device connection
+               hubName := obj1.GetType() + "." + obj1.Metadata.Name
+
+               // for each hub, add route (e.g. to obj2 via obj1)
+               hubs, _ := hub_manager.GetObjects(m)
+               for _, hub_obj := range hubs {
+                       if hub_obj.GetMetadata().Name != obj1.GetMetadata().Name {
+                               resutil.AddResource(hub_obj, "create", &resource.RouteResource {
+                                       Name: obj2_ip + "-" + obj1_ip,
+                                       Destination: obj2_ip,
+                                       Device: "vti_" + obj1_ip, // Todo: use the right ifname
+                                       Table: "default", // Todo: need check
+                               })
+                       }
+               }
+               // for each edge connect to obj1 (1) add route( e.g. to obj2 via obj1) (2) add SNAT (e.g. to obj2 --to-source edge ip) 
+               dev_names, _ := hubConn.GetConnectedDevices(overlay_name, obj1.Metadata.Name)
+               mm := make(map[string]string)
+               mm[OverlayResource] = overlay_name
+
+               for _, dev_name := range dev_names {
+                       strs := strings.SplitN(dev_name, "..", 2)
+                       if len(strs) == 2 {
+                               mm[DeviceResource] = strings.Replace(strs[0], "Device.", "", 1)
+                               dev_obj, err := dev_manager.GetObject(mm)
+                               dev := dev_obj.(*module.DeviceObject)
+                               if err == nil {
+                                       log.Println("Route Rule in " + strs[0] + " : " + obj2_ip + " via " + obj1.Metadata.Name)
+                                       resutil.AddResource(dev_obj, "create", &resource.RouteResource {
+                                               Name: obj2_ip + "-" + obj1_ip,
+                                               Destination: obj2_ip,
+                                               Device: "#" + dev.Status.Ip, // Todo: how to get net1
+                                               Table: "cnf", // Todo: need check
+                                       })
+
+                                       log.Println("NAT Rule in " + strs[0] + " to " + obj2.Metadata.Name )
+                                       resutil.AddResource(dev_obj, "create", &resource.FirewallNatResource {
+                                               Name: obj2_ip + "-" + dev.Metadata.Name,
+                                               DestinationIP: obj2_ip,
+                                               Dest: "#source",
+                                               SourceDestIP: dev.Status.DataIps[hubName],
+                                               Index: "1",
+                                               Target: "SNAT",
+                                       })
+
+                                       log.Println("Route Rule in " + obj2_ip + " to " + dev.Metadata.Name)
+                                       resutil.AddResource(obj2, "create", &resource.RouteResource {
+                                               Name: dev.Status.DataIps[hubName] + "-" + obj1_ip,
+                                               Destination: dev.Status.DataIps[hubName],
+                                               Device: "#" + obj2.Status.Ip,
+                                               Table: "cnf",
+                                       })
+
+                                       log.Println("NAT Rule in " + obj2_ip + " to " + dev.Metadata.Name )
+                                       resutil.AddResource(obj2, "create", &resource.FirewallNatResource {
+                                               Name: dev.Status.DataIps[hubName] + "-" + obj2.Metadata.Name,
+                                               DestinationIP: dev.Status.DataIps[hubName],
+                                               Dest: "#source",
+                                               SourceDestIP: obj2_ip,
+                                               Index: "1",
+                                               Target: "SNAT",
+                                       })
+
+                               } else {
+                                       log.Println("error in getting device")
+                                       log.Println(err)
+                               }
+                       }
+               }
+
+               if is_delegated {
+                       log.Println("adding rules for delegate connections")
+                       resutil.AddResource(m2, "create", &resource.RouteResource {
+                               Name: "default4" + obj2.Metadata.Name,
+                               Destination: "default",
+                               Gateway: obj1_ip,
+                               Device: "#" + obj2_ip,
+                               Table: "cnf",
+                       })
+                       resutil.AddResource(m2, "create", &resource.FirewallNatResource {
+                               Name: "default4" + obj2.Metadata.Name,
+                               SourceDestIP: obj2_ip,
+                               Dest: "#source",
+                               Index: "0",
+                               Target: "SNAT",
+                       })
+               }
        case DEVICETODEVICE:
                obj1 := m1.(*module.DeviceObject)
                obj2 := m2.(*module.DeviceObject)
 
-               obj1_ip := obj1.Status.Ip
-               obj2_ip := obj2.Status.Ip
+               obj1_ip = obj1.Status.Ip
+               obj2_ip = obj2.Status.Ip
 
                //Keypair
                obj1_crt, obj1_key, err := GetDeviceCertificate(m[OverlayResource], obj1.Metadata.Name)
@@ -418,7 +547,7 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                conn := resource.Connection{
                        Name:           DEFAULT_CONN + format_resource_name(obj1.Metadata.Name, obj2.Metadata.Name),
                        ConnectionType: CONN_TYPE,
-                       Mode:           MODE,
+                       Mode:           START_MODE,
                        Mark:           DEFAULT_MARK,
                        LocalUpDown:    DEFAULT_UPDOWN,
                        CryptoProposal: all_proposals,
@@ -455,21 +584,17 @@ func (c *OverlayObjectManager) SetupConnection(m map[string]string, m1 module.Co
                return pkgerrors.New("Unknown connection type")
        }
 
+       resutil.AddResource(m1, "create", &obj1_ipsec_resource)
+       resutil.AddResource(m2, "create", &obj2_ipsec_resource)
+
+       log.Println("cend1 ip:", obj1_ip)
+       log.Println("cend2 ip:", obj2_ip)
        cend1 := module.NewConnectionEnd(m1, obj1_ip)
        cend2 := module.NewConnectionEnd(m2, obj2_ip)
-
-       cend1.AddResource(&obj1_ipsec_resource, false)
-       cend2.AddResource(&obj2_ipsec_resource, false)
-
-       for i := 0; i < len(proposalresources); i++ {
-               cend1.AddResource(proposalresources[i], true)
-               cend2.AddResource(proposalresources[i], true)
-       }
-
        co := module.NewConnectionObject(cend1, cend2)
 
        cm := GetConnectionManager()
-       err = cm.Deploy(m[OverlayResource], co)
+       err = cm.Deploy(m[OverlayResource], co, resutil)
        if err != nil {
                return pkgerrors.Wrap(err, "Unable to create the object: fail to deploy resource")
        }
diff --git a/central-controller/src/scc/pkg/manager/resource_objectmanager.go b/central-controller/src/scc/pkg/manager/resource_objectmanager.go
new file mode 100644 (file)
index 0000000..0c36968
--- /dev/null
@@ -0,0 +1,103 @@
+/*\r
+ * Copyright 2020 Intel Corporation, Inc\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package manager\r
+\r
+import (\r
+       "encoding/json"\r
+       "io"\r
+\r
+       "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"\r
+       "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db"\r
+)\r
+\r
+type ResourceObjectKey struct {\r
+       Cluster string `json:"cluster-info"`\r
+       Type    string `json:"type"`\r
+       Name    string `json:"name"`\r
+}\r
+\r
+// ResourceObjectManager implements the ControllerObjectManager\r
+type ResourceObjectManager struct {\r
+       BaseObjectManager\r
+}\r
+\r
+func NewResourceObjectManager() *ResourceObjectManager {\r
+       return &ResourceObjectManager{\r
+               BaseObjectManager{\r
+                       storeName:      StoreName,\r
+                       tagMeta:        "resource",\r
+                       depResManagers: []ControllerObjectManager{},\r
+                       ownResManagers: []ControllerObjectManager{},\r
+               },\r
+       }\r
+}\r
+\r
+func (c *ResourceObjectManager) GetResourceName() string {\r
+       return Resource\r
+}\r
+\r
+func (c *ResourceObjectManager) IsOperationSupported(oper string) bool {\r
+       return false\r
+}\r
+\r
+func (c *ResourceObjectManager) CreateEmptyObject() module.ControllerObject {\r
+       return &module.ResourceObject{}\r
+}\r
+\r
+func (c *ResourceObjectManager) GetStoreKey(m map[string]string, t module.ControllerObject, isCollection bool) (db.Key, error) {\r
+       return ResourceObjectKey{\r
+               Cluster: m[OverlayResource] + "-" + m[DeviceResource],\r
+               Type:  m["Type"],\r
+               Name:  m["Name"],\r
+       }, nil\r
+}\r
+\r
+func (c *ResourceObjectManager) ParseObject(r io.Reader) (module.ControllerObject, error) {\r
+       var v module.ResourceObject\r
+       err := json.NewDecoder(r).Decode(&v)\r
+       return &v, err\r
+}\r
+\r
+func (c *ResourceObjectManager) CreateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) {\r
+       // DB Operation\r
+       t, err := GetDBUtils().CreateObject(c, m, t)\r
+       return t, err\r
+}\r
+\r
+func (c *ResourceObjectManager) GetObject(m map[string]string) (module.ControllerObject, error) {\r
+       // DB Operation\r
+       t, err := GetDBUtils().GetObject(c, m)\r
+       return t, err\r
+}\r
+\r
+func (c *ResourceObjectManager) GetObjects(m map[string]string) ([]module.ControllerObject, error) {\r
+       // DB Operation\r
+       t, err := GetDBUtils().GetObjects(c, m)\r
+       return t, err\r
+}\r
+\r
+func (c *ResourceObjectManager) UpdateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) {\r
+       // DB Operation\r
+       t, err := GetDBUtils().UpdateObject(c, m, t)\r
+       return t, err\r
+}\r
+\r
+func (c *ResourceObjectManager) DeleteObject(m map[string]string) error {\r
+       // DB Operation\r
+       err := GetDBUtils().DeleteObject(c, m)\r
+       return err\r
+}\r
index 2103130..212aba1 100644 (file)
 package manager
 
 import (
+       "crypto/sha256"
+
        rsyncclient "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/client"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module"
        "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/resource"
        "github.com/open-ness/EMCO/src/orchestrator/pkg/resourcestatus"
 
        "github.com/open-ness/EMCO/src/orchestrator/pkg/appcontext"
-       //    rsyncclient "github.com/open-ness/EMCO/src/orchestrator/pkg/grpc/installappclient"
        "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/rpc"
        controller "github.com/open-ness/EMCO/src/orchestrator/pkg/module/controller"
 
@@ -34,17 +35,20 @@ import (
        "fmt"
        pkgerrors "github.com/pkg/errors"
        "log"
+       "sync"
        "time"
 )
 
 var rsync_initialized = false
 var provider_name = "akraino_scc"
 var project_name = "akraino_scc"
+var Resource_mux  = sync.Mutex{}
 
 // sdewan definition
 type DeployResource struct {
        Action   string
        Resource resource.ISdewanResource
+       Status   int // 0: to be (un)deployed; 1: success; 2: failed
 }
 
 type DeployResources struct {
@@ -115,6 +119,10 @@ func makeAppContextForCompositeApp(p, ca, v, rName, dig string, namespace string
        return cca, nil
 }
 
+func getResourceName(resource DeployResource) string {
+       return resource.Resource.GetName() + "+" + resource.Resource.GetType()
+}
+
 func addResourcesToCluster(ct appcontext.AppContext, ch interface{}, target string, resources []DeployResource, isDeploy bool) error {
 
        var resOrderInstr struct {
@@ -127,13 +135,11 @@ func addResourcesToCluster(ct appcontext.AppContext, ch interface{}, target stri
        resdep := make(map[string]string)
 
        for _, resource := range resources {
-               resource_name := resource.Resource.GetName() + "+" + resource.Resource.GetType()
+               resource_name := getResourceName(resource)
                resource_data := resource.Resource.ToYaml(target)
                resOrderInstr.Resorder = append(resOrderInstr.Resorder, resource_name)
                resdep[resource_name] = "go"
-               // rtc.RtcAddResource("<cid>/app/app_name/cluster/clusername/", res.name, res.content)
-               // -> save ("<cid>/app/app_name/cluster/clusername/resource/res.name/", res.content) in etcd
-               // return ("<cid>/app/app_name/cluster/clusername/resource/res.name/"
+
                rh, err := ct.AddResource(ch, resource_name, resource_data)
                if isDeploy == false {
                        //Delete resource
@@ -149,9 +155,7 @@ func addResourcesToCluster(ct appcontext.AppContext, ch interface{}, target stri
                jresOrderInstr, _ := json.Marshal(resOrderInstr)
                resDepInstr.Resdep = resdep
                jresDepInstr, _ := json.Marshal(resDepInstr)
-               // rtc.RtcAddInstruction("<cid>app/app_name/cluster/clusername/", "resource", "order", "{[res.name]}")
-               // ->save ("<cid>/app/app_name/cluster/clusername/resource/instruction/order/", "{[res.name]}") in etcd
-               // return "<cid>/app/app_name/cluster/clusername/resource/instruction/order/"
+
                _, err = ct.AddInstruction(ch, "resource", "order", string(jresOrderInstr))
                _, err = ct.AddInstruction(ch, "resource", "dependency", string(jresDepInstr))
                if err != nil {
@@ -210,12 +214,16 @@ func (d *ResUtil) contains(reses []DeployResource, res DeployResource) bool {
        return false
 }
 
+func (d *ResUtil) GetResources() map[module.ControllerObject]*DeployResources {
+       return d.resmap
+}
+
 func (d *ResUtil) AddResource(device module.ControllerObject, action string, resource resource.ISdewanResource) error {
        if d.resmap[device] == nil {
                d.resmap[device] = &DeployResources{Resources: []DeployResource{}}
        }
 
-       ds := DeployResource{Action: action, Resource: resource}
+       ds := DeployResource{Action: action, Resource: resource, Status: 0}
        if !d.contains(d.resmap[device].Resources, ds) {
                d.resmap[device].Resources = append(d.resmap[device].Resources, ds)
        }
@@ -226,9 +234,17 @@ func (d *ResUtil) TargetName(o module.ControllerObject) string {
        return o.GetType() + "." + o.GetMetadata().Name
 }
 
-func (d *ResUtil) Deploy(app_name string, format string) (string, error) {
-       // Generate Application context
-       cca, err := makeAppContextForCompositeApp(project_name, app_name+"-d", "1.0", "1.0", "di", "default", "0")
+func (d *ResUtil) getDeviceAppName(device module.ControllerObject) string {
+       return device.GetMetadata().Name + "-app"
+}
+
+func (d *ResUtil) getDeviceClusterName(device module.ControllerObject) string {
+       return provider_name + "+" + device.GetMetadata().Name
+}
+
+func (d *ResUtil) DeployOneResource(app_name string, format string, device module.ControllerObject, resource DeployResource) (string, error) {
+       resource_app_name := app_name + resource.Resource.GetName()
+       cca, err := makeAppContextForCompositeApp(project_name, resource_app_name, "1.0", "1.0", "di", "default", "0")
        context := cca.context                    // appcontext.AppContext
        ctxval := cca.ctxval                      // id
        compositeHandle := cca.compositeAppHandle // cid
@@ -240,25 +256,14 @@ func (d *ResUtil) Deploy(app_name string, format string) (string, error) {
                Appdep map[string]string `json:"appdependency"`
        }
        appdep := make(map[string]string)
-       // create a com_app for each device
-       for device, res := range d.resmap {
-               // Add application
-               app_name := device.GetMetadata().Name + "-app"
-               appOrderInstr.Apporder = append(appOrderInstr.Apporder, app_name)
-               appdep[app_name] = "go"
+       device_app_name := d.getDeviceAppName(device)
+       appOrderInstr.Apporder = append(appOrderInstr.Apporder, device_app_name)
+       appdep[device_app_name] = "go"
 
-               // rtc.RtcAddLevel(cid, "app", app_name) -> save ("<cid>app/app_name/", app_name) in etcd
-               // apphandle = "<cid>app/app_name/"
-               apphandle, _ := context.AddApp(compositeHandle, app_name)
+       apphandle, _ := context.AddApp(compositeHandle, device_app_name)
 
-               // Add cluster
-               // err = addClustersToAppContext(listOfClusters, context, apphandle, resources)
-               // rtc.RtcAddLevel("<cid>app/app_name/", "cluster", clustername)
-               // -> save ("<cid>app/app_name/cluster/clusername/", clustername) in etcd
-               // return "<cid>app/app_name/cluster/clusername/"
-               clusterhandle, _ := context.AddCluster(apphandle, provider_name+"+"+device.GetMetadata().Name)
-               err = addResourcesToCluster(context, clusterhandle, d.TargetName(device), res.Resources, true)
-       }
+       clusterhandle, _ := context.AddCluster(apphandle, d.getDeviceClusterName(device))
+       err = addResourcesToCluster(context, clusterhandle, d.TargetName(device), []DeployResource{resource}, true)
 
        jappOrderInstr, _ := json.Marshal(appOrderInstr)
        appDepInstr.Appdep = appdep
@@ -271,55 +276,187 @@ func (d *ResUtil) Deploy(app_name string, format string) (string, error) {
        err = rsyncclient.InvokeInstallApp(appContextID)
        if err != nil {
                log.Println(err)
-               return appContextID, err
+               cleanuperr := context.DeleteCompositeApp()
+               if cleanuperr != nil {
+                       log.Printf(":: Error Cleaning up AppContext after add instruction failure ::")
+               }
+
+               return "", err
        }
 
        return appContextID, nil
 }
 
-func (d *ResUtil) Undeploy(app_name string, format string) (string, error) {
-       // Generate Application context
-       cca, err := makeAppContextForCompositeApp(project_name, app_name+"-u", "1.0", "1.0", "di", "default", "0")
-       context := cca.context                    // appcontext.AppContext
-       ctxval := cca.ctxval                      // id
-       compositeHandle := cca.compositeAppHandle // cid
+func (d *ResUtil) UpdateOneResource(cid string, device module.ControllerObject, resourceName string, resourceValue string) error {
+       context := appcontext.AppContext{}
+       _, err := context.LoadAppContext(cid)
+       if err != nil {
+               return err
+       }
 
-       var appOrderInstr struct {
-               Apporder []string `json:"apporder"`
+       rh, err := context.GetResourceHandle(d.getDeviceAppName(device), d.getDeviceClusterName(device), resourceName)
+       if err != nil {
+               return err
        }
-       var appDepInstr struct {
-               Appdep map[string]string `json:"appdependency"`
+
+       err = context.UpdateResourceValue(rh, resourceValue)
+       if err != nil {
+               return err
        }
-       appdep := make(map[string]string)
-       // create a com_app for each device
+
+       err = rsyncclient.InvokeInstallApp(cid)
+       return err
+}
+
+func (d *ResUtil) Deploy(overlay string, app_name string, format string) error {
+       isErr := false
+       errMessage := "Failed:"
+       res_manager := GetManagerset().Resource
+       m := make(map[string]string)
+       m[OverlayResource] = overlay
+
+       Resource_mux.Lock()
+       defer Resource_mux.Unlock()
+
        for device, res := range d.resmap {
-               // Add application
-               app_name := device.GetMetadata().Name + "-app"
-               appOrderInstr.Apporder = append(appOrderInstr.Apporder, app_name)
-               appdep[app_name] = "go"
-               apphandle, _ := context.AddApp(compositeHandle, app_name)
+               m[DeviceResource] = device.GetType() + "." + device.GetMetadata().Name
+
+               for _, resource := range res.Resources {
+                       operation := 1
+                       m["Name"] = resource.Resource.GetName()
+                       m["Type"] = resource.Resource.GetType()
+                       robj, err := res_manager.GetObject(m)
+                       resobj := robj.(*module.ResourceObject)
+                       if err != nil {
+                               // create a new resource object
+                               resobj.Metadata.Name = m["Name"]
+                               resobj.Specification.Hash = ""
+                               resobj.Specification.ContextId = ""
+                               resobj.Specification.Ref = 0
+                               resobj.Specification.Status = Resource_Status_NotDeployed
+                       }
 
-               // Add cluster
-               clusterhandle, _ := context.AddCluster(apphandle, provider_name+"+"+device.GetMetadata().Name)
-               err = addResourcesToCluster(context, clusterhandle, d.TargetName(device), res.Resources, false)
+                       resource_data := resource.Resource.ToYaml(d.TargetName(device))
+                       resource_data_hash_byte := sha256.Sum256([]byte(resource_data))
+                       resource_data_hash := string(resource_data_hash_byte[:])
+                       if resobj.Specification.Ref > 0 && resource_data_hash != resobj.Specification.Hash {
+                               operation = 2
+                       }
+
+                       switch operation {
+                       case 1:
+                               // Add resource
+                               if resource.Status != 1 {
+                                       // resource is not deployed or failed to deploy
+                                       if resobj.Specification.Ref == 0 {
+                                               // resource needs to be deployed        
+                                               cid, err := d.DeployOneResource(app_name, format, device, resource)
+
+                                               if err != nil {
+                                                       isErr = true
+                                                       resource.Status = 2
+                                                       errMessage = errMessage + " " + resource.Resource.GetName()
+                                               } else {
+                                                       resource.Status = 1
+                                                       resobj.Specification.Hash = resource_data_hash
+                                                       resobj.Specification.ContextId = cid
+                                                       resobj.Specification.Ref = 1
+                                                       resobj.Specification.Status = Resource_Status_Deployed
+
+                                                       res_manager.CreateObject(m, resobj)
+                                               }
+                                       } else {
+                                               // add ref
+                                               resobj.Specification.Ref += 1
+                                               resource.Status = 1
+                                               res_manager.UpdateObject(m, resobj)
+                                       }
+                               }
+                       case 2:
+                               // Update resource
+                               if resource.Status != 1 {
+                                       err := d.UpdateOneResource(resobj.Specification.ContextId, device, getResourceName(resource), resource_data)
+                                       if err != nil {
+                                               isErr = true
+                                               resource.Status = 2
+                                               errMessage = errMessage + " " + resource.Resource.GetName()
+                                               log.Println(err)
+                                       } else {
+                                               resource.Status = 1
+                                               // add ref
+                                               resobj.Specification.Hash = resource_data_hash
+                                               resobj.Specification.Ref += 1
+
+                                               res_manager.UpdateObject(m, resobj)
+                                       }
+                               }
+                       default:
+                               log.Println("Unknown operation type")
+                       }
+               }
        }
 
-       jappOrderInstr, _ := json.Marshal(appOrderInstr)
-       appDepInstr.Appdep = appdep
-       jappDepInstr, _ := json.Marshal(appDepInstr)
-       context.AddInstruction(compositeHandle, "app", "order", string(jappOrderInstr))
-       context.AddInstruction(compositeHandle, "app", "dependency", string(jappDepInstr))
+       if isErr {
+               return pkgerrors.New(errMessage)
+       }
+       return nil
+}
 
-       initializeAppContextStatus(context, appcontext.AppContextStatus{Status: appcontext.AppContextStatusEnum.Instantiated})
-       // invoke deployment process
-       appContextID := fmt.Sprintf("%v", ctxval)
-       err = rsyncclient.InvokeUninstallApp(appContextID)
-       if err != nil {
-               log.Println(err)
-               return appContextID, err
+func (d *ResUtil) Undeploy(overlay string) error {
+       isErr := false
+       errMessage := "Failed:"
+       res_manager := GetManagerset().Resource
+       m := make(map[string]string)
+       m[OverlayResource] = overlay
+
+       Resource_mux.Lock()
+       defer Resource_mux.Unlock()
+
+       for device, res := range d.resmap {
+               m[DeviceResource] = device.GetType() + "." + device.GetMetadata().Name
+
+               // Use reversed order to do undeploy
+               for i:=len(res.Resources)-1; i>=0; i-- {
+               // for _, resource := range res.Resources {
+                       resource := res.Resources[i]
+                       m["Name"] = resource.Resource.GetName()
+                       m["Type"] = resource.Resource.GetType()
+                       robj, err := res_manager.GetObject(m)
+                       resobj := robj.(*module.ResourceObject)
+                       if err != nil || resobj.Specification.Ref <= 0 {
+                               // resource had not been deployed before, nothing to do
+                               log.Println("Resource " + resource.Resource.GetName() + " hasn't been deployed, ignore the operation")
+                               continue
+                       }
+
+                       if resource.Status != 1 {
+                               // resource is not undeployed or failed to undeploy
+                               if resobj.Specification.Ref <= 1 {
+                                       err = rsyncclient.InvokeUninstallApp(resobj.Specification.ContextId)
+                                       if err != nil {
+                                               log.Println(err)
+                                               isErr = true
+                                               resource.Status = 2
+                                               errMessage = errMessage + " " + resource.Resource.GetName()
+                                       } else {
+                                               // reset rewource status
+                                               resource.Status = 1
+                                               resobj.Specification.Ref = 0
+                                               res_manager.DeleteObject(m)
+                                       }
+                               } else {
+                                       resobj.Specification.Ref -= 1
+                                       resource.Status = 1
+                                       res_manager.UpdateObject(m, resobj)
+                               }
+                       }
+               }
        }
 
-       return appContextID, nil
+       if isErr {
+               return pkgerrors.New(errMessage)
+       }
+       return nil
 }
 
 func (d *ResUtil) AddQueryResource(device module.ControllerObject, resource QueryResource) error {
index 466b3ff..e507967 100644 (file)
@@ -17,7 +17,6 @@
 package module
 
 import (
-       "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/resource"
        "log"
 )
 
@@ -35,6 +34,12 @@ var StateEnum = &states{
        Error:      "Error",
 }
 
+type ConnectionResource struct {
+       ConnObject  string  `json:"-"`
+       Name        string  `json:"-"`
+       Type        string  `json:"-"`
+}
+
 type ConnectionObject struct {
        Metadata ObjectMetaData `json:"metadata"`
        Info     ConnectionInfo `json:"information"`
@@ -44,7 +49,7 @@ type ConnectionObject struct {
 type ConnectionInfo struct {
        End1         ConnectionEnd `json:"end1"`
        End2         ConnectionEnd `json:"end2"`
-       ContextId    string        `json:"-"`
+       Resources    []ConnectionResource `json:"-"`
        State        string        `json:"state"`
        ErrorMessage string        `json:"message"`
 }
@@ -54,8 +59,6 @@ type ConnectionEnd struct {
        Type        string   `json:"type"`
        IP          string   `json:"ip"`
        ConnObject  string   `json:"-"`
-       Resources   []string `json:"-"`
-       ReservedRes []string `json:"-"`
 }
 
 func (c *ConnectionObject) GetMetadata() ObjectMetaData {
@@ -66,6 +69,20 @@ func (c *ConnectionObject) GetType() string {
        return "Connection"
 }
 
+func (c *ConnectionObject) GetPeer(t string, n string) (string, string, string) {
+       e1 := c.Info.End1
+       e2 := c.Info.End2
+       if e1.Type == t && e1.Name == CreateEndName(t, n) {
+               return e2.Type, e2.Name, e2.IP
+       } else {
+               if e2.Type == t && e2.Name == CreateEndName(t, n) {
+                       return e1.Type, e1.Name, e1.IP
+               }
+       }
+
+       return "", "", ""
+}
+
 func CreateEndName(t string, n string) string {
        return t + "." + n
 }
@@ -82,8 +99,6 @@ func NewConnectionEnd(conn_obj ControllerObject, ip string) ConnectionEnd {
                        Type:        conn_obj.GetType(),
                        IP:          ip,
                        ConnObject:  obj_str,
-                       Resources:   []string{},
-                       ReservedRes: []string{},
                }
        } else {
                log.Println(err)
@@ -97,50 +112,18 @@ func NewConnectionObject(end1 ConnectionEnd, end2 ConnectionEnd) ConnectionObjec
                Info: ConnectionInfo{
                        End1:         end1,
                        End2:         end2,
-                       ContextId:    "",
+                       Resources:    []ConnectionResource{},
                        State:        StateEnum.Created,
                        ErrorMessage: "",
                },
        }
 }
 
-func (c *ConnectionEnd) contains(res resource.ISdewanResource, isReserved bool) bool {
-       if isReserved {
-               for _, r_str := range c.ReservedRes {
-                       r, err := resource.GetResourceBuilder().ToObject(r_str)
-                       if err == nil {
-                               if r.GetName() == res.GetName() &&
-                                       r.GetType() == res.GetType() {
-                                       return true
-                               }
-                       }
-               }
+func (c *ConnectionInfo) AddResource(device ControllerObject, resource string, res_type string) {
+       dev_str, err := GetObjectBuilder().ToString(device)
+       if err == nil {
+               c.Resources = append(c.Resources, ConnectionResource{dev_str, resource, res_type})
        } else {
-               for _, r_str := range c.Resources {
-                       r, err := resource.GetResourceBuilder().ToObject(r_str)
-                       if err == nil {
-                               if r.GetName() == res.GetName() &&
-                                       r.GetType() == res.GetType() {
-                                       return true
-                               }
-                       }
-               }
-       }
-
-       return false
-}
-
-func (c *ConnectionEnd) AddResource(res resource.ISdewanResource, isReserved bool) error {
-       if !c.contains(res, isReserved) {
-               res_str, err := resource.GetResourceBuilder().ToString(res)
-               if err == nil {
-                       if isReserved {
-                               c.ReservedRes = append(c.ReservedRes, res_str)
-                       } else {
-                               c.Resources = append(c.Resources, res_str)
-                       }
-               }
+               log.Println(err)
        }
-
-       return nil
 }
index 53783de..82fc300 100644 (file)
@@ -47,6 +47,7 @@ type DeviceObjectStatus struct {
        DataIps map[string]string
        // Status Data
        Data map[string]string
+       DelegatedHub string
 }
 
 func (c *DeviceObject) GetMetadata() ObjectMetaData {
index 876b45a..3b681bb 100644 (file)
@@ -24,7 +24,8 @@ type HubDeviceObject struct {
 
 //HubDeviceObjectSpec contains the parameters
 type HubDeviceObjectSpec struct {
-       Device string `json:"device"`
+       Device        string `json:"device"`
+       IsDelegateHub bool `json:"isDelegateHub"`
 }
 
 func (c *HubDeviceObject) GetMetadata() ObjectMetaData {
index 70d221e..3e44e3d 100644 (file)
 
 package module
 
-import (
-       pkgerrors "github.com/pkg/errors"
-       "strconv"
-)
-
 const (
        MinProxyPort = 10000
        MaxProxyPort = 16000
@@ -44,8 +39,8 @@ type HubObjectSpec struct {
 type HubObjectStatus struct {
        Ip   string
        Data map[string]string
-       // Allocated proxy port for device
-       ProxyPort map[string]string
+       // Devices that this hub delegates
+       DelegateDevices []string
 }
 
 func (c *HubObject) GetMetadata() ObjectMetaData {
@@ -60,33 +55,6 @@ func (c *HubObject) GetType() string {
        return "Hub"
 }
 
-func (c *HubObject) IsProxyPortUsed(port int) bool {
-       _, ok := c.Status.ProxyPort[strconv.Itoa(port)]
-       return ok
-}
-
-func (c *HubObject) SetProxyPort(port int, device string) {
-       c.Status.ProxyPort[strconv.Itoa(port)] = device
-}
-
-func (c *HubObject) UnsetProxyPort(port int) {
-       delete(c.Status.ProxyPort, strconv.Itoa(port))
-}
-
-func (c *HubObject) GetProxyPort(port int) string {
-       return c.Status.ProxyPort[strconv.Itoa(port)]
-}
-
-func (c *HubObject) AllocateProxyPort() (int, error) {
-       for i := MinProxyPort; i < MaxProxyPort; i++ {
-               if !c.IsProxyPortUsed(i) {
-                       return i, nil
-               }
-       }
-
-       return 0, pkgerrors.New("Fail to allocate proxy port")
-}
-
 func init() {
        GetObjectBuilder().Register("Hub", &HubObject{})
 }
diff --git a/central-controller/src/scc/pkg/module/resourceobject.go b/central-controller/src/scc/pkg/module/resourceobject.go
new file mode 100644 (file)
index 0000000..9b7587d
--- /dev/null
@@ -0,0 +1,39 @@
+/*\r
+ * Copyright 2020 Intel Corporation, Inc\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package module\r
+\r
+// App contains metadata for Apps\r
+type ResourceObject struct {\r
+       Metadata      ObjectMetaData    `json:"metadata"`\r
+       Specification ResourceObjectSpec `json:"spec"`\r
+}\r
+\r
+//ResourceObjectSpec contains the parameters\r
+type ResourceObjectSpec struct {\r
+       Hash             string   `json:"hash"`\r
+       Ref                      int      `json:"ref"`\r
+       ContextId                string      `json:"cid"`\r
+       Status                   string      `json:"status"`\r
+}\r
+\r
+func (c *ResourceObject) GetMetadata() ObjectMetaData {\r
+       return c.Metadata\r
+}\r
+\r
+func (c *ResourceObject) GetType() string {\r
+       return "Resource"\r
+}
\ No newline at end of file
index 52db254..e6983e9 100644 (file)
@@ -19,14 +19,16 @@ package resource
 import ()
 
 type EmptyResource struct {
+       Name     string
+       Type     string
 }
 
 func (c *EmptyResource) GetName() string {
-       return ""
+       return c.Name
 }
 
 func (c *EmptyResource) GetType() string {
-       return "Empty"
+       return c.Type
 }
 
 func (c *EmptyResource) ToYaml(target string) string {
diff --git a/central-controller/src/scc/pkg/resource/firewall_nat_resource.go b/central-controller/src/scc/pkg/resource/firewall_nat_resource.go
new file mode 100644 (file)
index 0000000..46784d3
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package resource
+
+import ()
+
+type FirewallNatResource struct {
+       Name            string
+       Source          string
+       SourceIP        string
+       SourcePort      string
+       SourceDestIP    string
+       SourceDestPort  string
+       Dest            string
+       DestinationIP   string
+       DestinationPort string
+       Protocol        string
+       Target          string
+       Index           string
+}
+
+func (c *FirewallNatResource) GetName() string {
+       return c.Name
+}
+
+func (c *FirewallNatResource) GetType() string {
+       return "FirewallNAT"
+}
+
+func (c *FirewallNatResource) ToYaml(target string) string {
+       basic := `apiVersion: ` + SdewanApiVersion + `
+kind: CNFNAT
+metadata:
+  name: ` + c.Name + `
+  namespace: default
+  labels:
+    sdewanPurpose: ` + SdewanPurpose + `
+    targetCluster: ` + target + `
+spec:
+  target: ` + c.Target + `
+  src_dip: ` + c.SourceDestIP
+        if c.DestinationIP != "" {
+               basic += `
+  dest_ip: ` + c.DestinationIP
+        }
+
+        if c.DestinationPort != "" {
+               basic += `
+  dest_port: ` + c.DestinationPort
+        }
+       if c.Dest != "" {
+               basic += `
+  dest: "` + c.Dest + `"`
+        }
+       if c.SourceDestPort != "" {
+               basic += `
+  src_dport: ` + c.SourceDestPort
+        }
+       if c.Protocol != "" {
+               basic += `
+  proto: ` + c.Protocol
+       }
+       if c.Source != "" {
+               basic += `
+  src: "` + c.Source + `"`
+        }
+       if c.SourceIP != "" {
+               basic += `
+  src_ip: ` + c.SourceIP
+       }
+       if c.Index != "" {
+               basic += `
+  index: "` + c.Index + `"`
+        }
+
+       return basic
+}
+
+func init() {
+       GetResourceBuilder().Register("FirewallNat", &FirewallNatResource{})
+}
index 59cab05..2928429 100644 (file)
@@ -84,11 +84,11 @@ spec:
   type: ` + c.Type + `
   remote: '` + c.Remote + `'
   authentication_method: ` + c.AuthenticationMethod + `
-  force_crypto_proposal: "` + c.ForceCryptoProposal + `
+  force_crypto_proposal: "` + c.ForceCryptoProposal + `"
   crypto_proposal: [` + p + `]`
 
                connection = `
-  connections: 
+  connections:
   - name: ` + c.Connections.Name + `
     conn_type: ` + c.Connections.ConnectionType + `
     mode: ` + c.Connections.Mode + `
@@ -99,10 +99,16 @@ spec:
 
                if c.Connections.RemoteSourceIp != "" {
                        remote_source_ip := `
-    remote_source_ip: '` + c.Connections.RemoteSourceIp + `'`
+    remote_sourceip: '` + c.Connections.RemoteSourceIp + `'`
                        connection += remote_source_ip
                }
 
+               if c.Connections.RemoteSubnet != "" {
+                       remote_subnet := `
+    remote_subnet: '` + c.Connections.RemoteSubnet + `'`
+                       connection += remote_subnet
+               }
+
                if c.AuthenticationMethod == AuthTypePUBKEY {
                        auth := `
   local_public_cert: ` + c.PublicCert + `
@@ -165,6 +171,12 @@ spec:
                connection += remote_source_ip
        }
 
+       if c.Connections.RemoteSubnet != "" {
+               remote_subnet := `
+    remote_subnet: '` + c.Connections.RemoteSubnet + `'`
+               connection += remote_subnet
+       }
+
        if c.AuthenticationMethod == AuthTypePUBKEY {
                auth := `
   local_public_cert: ` + c.PublicCert + `
index 06abc40..b048555 100644 (file)
@@ -50,11 +50,11 @@ func (c *ResourceBuilder) ToString(obj ISdewanResource) (string, error) {
 
 func (c *ResourceBuilder) ToObject(obj_str string) (ISdewanResource, error) {
        if !strings.Contains(obj_str, "-") {
-               return &EmptyResource{}, pkgerrors.New("Not a valid object")
+               return &EmptyResource{"", ""}, pkgerrors.New("Not a valid object")
        }
        strs := strings.SplitN(obj_str, "-", 2)
        if len(strs) != 2 {
-               return &EmptyResource{}, pkgerrors.New("Not a valid object")
+               return &EmptyResource{"", ""}, pkgerrors.New("Not a valid object")
        }
 
        if v, ok := c.omap[strs[0]]; ok {
@@ -62,6 +62,6 @@ func (c *ResourceBuilder) ToObject(obj_str string) (ISdewanResource, error) {
                err := json.Unmarshal([]byte(strs[1]), retObj)
                return retObj.(ISdewanResource), err
        } else {
-               return &EmptyResource{}, pkgerrors.New("Not a valid object")
+               return &EmptyResource{"", ""}, pkgerrors.New("Not a valid object")
        }
 }
diff --git a/central-controller/src/scc/pkg/resource/route_resource.go b/central-controller/src/scc/pkg/resource/route_resource.go
new file mode 100644 (file)
index 0000000..cf2794f
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+ * Copyright 2020 Intel Corporation, Inc\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package resource\r
+\r
+type RouteResource struct {\r
+       Name    string\r
+       Destination       string\r
+       Gateway string\r
+       Device       string\r
+       Table    string\r
+}\r
+\r
+func (c *RouteResource) GetName() string {\r
+       return c.Name\r
+}\r
+\r
+func (c *RouteResource) GetType() string {\r
+       return "Route"\r
+}\r
+\r
+func (c *RouteResource) ToYaml(target string) string {\r
+       basic := `apiVersion: ` + SdewanApiVersion + `\r
+kind: CNFRoute\r
+metadata:\r
+  name: ` + c.Name + `\r
+  namespace: default\r
+  labels:\r
+    sdewanPurpose: ` + SdewanPurpose + `\r
+    targetCluster: ` + target + `\r
+spec:\r
+  dst: ` + c.Destination + `\r
+  dev: "` + c.Device + `"\r
+  table: ` + c.Table\r
+\r
+       if c.Gateway != "" {\r
+              basic += `\r
+  gw: ` + c.Gateway\r
+  }\r
+       return basic\r
+}\r
+\r
+func init() {\r
+       GetResourceBuilder().Register("Route", &RouteResource{})\r
+}\r