From: Ruoyu Ying Date: Tue, 21 Dec 2021 08:49:29 +0000 (-0500) Subject: New changes in scc to support multi-hub X-Git-Tag: 21.12.02~4^2 X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=commitdiff_plain;h=b04a9441bb69151f36e29661b9c419787d8c022c;p=icn%2Fsdwan.git New changes in scc to support multi-hub Change-Id: I3479dd905eddbf5ff0d0b688e18ea9c8ada52b48 Signed-off-by: Ruoyu Ying --- diff --git a/central-controller/src/scc/api/api.go b/central-controller/src/scc/api/api.go index 648669f..b7be3e8 100644 --- a/central-controller/src/scc/api/api.go +++ b/central-controller/src/scc/api/api.go @@ -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) diff --git a/central-controller/src/scc/pkg/manager/connection_manager.go b/central-controller/src/scc/pkg/manager/connection_manager.go index cfccc4b..ea38552 100644 --- a/central-controller/src/scc/pkg/manager/connection_manager.go +++ b/central-controller/src/scc/pkg/manager/connection_manager.go @@ -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) diff --git a/central-controller/src/scc/pkg/manager/constants.go b/central-controller/src/scc/pkg/manager/constants.go index 230fc72..511372e 100644 --- a/central-controller/src/scc/pkg/manager/constants.go +++ b/central-controller/src/scc/pkg/manager/constants.go @@ -17,26 +17,29 @@ 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" ) diff --git a/central-controller/src/scc/pkg/manager/device_objectmanager.go b/central-controller/src/scc/pkg/manager/device_objectmanager.go index 4bf601a..547beea 100644 --- a/central-controller/src/scc/pkg/manager/device_objectmanager.go +++ b/central-controller/src/scc/pkg/manager/device_objectmanager.go @@ -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 } diff --git a/central-controller/src/scc/pkg/manager/hub_objectmanager.go b/central-controller/src/scc/pkg/manager/hub_objectmanager.go index db7e172..bdd66a6 100644 --- a/central-controller/src/scc/pkg/manager/hub_objectmanager.go +++ b/central-controller/src/scc/pkg/manager/hub_objectmanager.go @@ -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.") } diff --git a/central-controller/src/scc/pkg/manager/hubconnection_objectmanager.go b/central-controller/src/scc/pkg/manager/hubconnection_objectmanager.go index e858d7b..13569fc 100644 --- a/central-controller/src/scc/pkg/manager/hubconnection_objectmanager.go +++ b/central-controller/src/scc/pkg/manager/hubconnection_objectmanager.go @@ -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 +} diff --git a/central-controller/src/scc/pkg/manager/hubdevice_objectmanager.go b/central-controller/src/scc/pkg/manager/hubdevice_objectmanager.go index 821b6be..47b45b2 100644 --- a/central-controller/src/scc/pkg/manager/hubdevice_objectmanager.go +++ b/central-controller/src/scc/pkg/manager/hubdevice_objectmanager.go @@ -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)) diff --git a/central-controller/src/scc/pkg/manager/managerset.go b/central-controller/src/scc/pkg/manager/managerset.go index afbbb6e..fb0c09a 100644 --- a/central-controller/src/scc/pkg/manager/managerset.go +++ b/central-controller/src/scc/pkg/manager/managerset.go @@ -29,6 +29,7 @@ type Managerset struct { ProviderIPRange *IPRangeObjectManager IPRange *IPRangeObjectManager Cert *CertificateObjectManager + Resource *ResourceObjectManager } var mgrset = Managerset{} diff --git a/central-controller/src/scc/pkg/manager/overlay_objectmanager.go b/central-controller/src/scc/pkg/manager/overlay_objectmanager.go index 22e8c8b..41b1073 100644 --- a/central-controller/src/scc/pkg/manager/overlay_objectmanager.go +++ b/central-controller/src/scc/pkg/manager/overlay_objectmanager.go @@ -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 index 0000000..0c36968 --- /dev/null +++ b/central-controller/src/scc/pkg/manager/resource_objectmanager.go @@ -0,0 +1,103 @@ +/* + * 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 manager + +import ( + "encoding/json" + "io" + + "github.com/akraino-edge-stack/icn-sdwan/central-controller/src/scc/pkg/module" + "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/db" +) + +type ResourceObjectKey struct { + Cluster string `json:"cluster-info"` + Type string `json:"type"` + Name string `json:"name"` +} + +// ResourceObjectManager implements the ControllerObjectManager +type ResourceObjectManager struct { + BaseObjectManager +} + +func NewResourceObjectManager() *ResourceObjectManager { + return &ResourceObjectManager{ + BaseObjectManager{ + storeName: StoreName, + tagMeta: "resource", + depResManagers: []ControllerObjectManager{}, + ownResManagers: []ControllerObjectManager{}, + }, + } +} + +func (c *ResourceObjectManager) GetResourceName() string { + return Resource +} + +func (c *ResourceObjectManager) IsOperationSupported(oper string) bool { + return false +} + +func (c *ResourceObjectManager) CreateEmptyObject() module.ControllerObject { + return &module.ResourceObject{} +} + +func (c *ResourceObjectManager) GetStoreKey(m map[string]string, t module.ControllerObject, isCollection bool) (db.Key, error) { + return ResourceObjectKey{ + Cluster: m[OverlayResource] + "-" + m[DeviceResource], + Type: m["Type"], + Name: m["Name"], + }, nil +} + +func (c *ResourceObjectManager) ParseObject(r io.Reader) (module.ControllerObject, error) { + var v module.ResourceObject + err := json.NewDecoder(r).Decode(&v) + return &v, err +} + +func (c *ResourceObjectManager) CreateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) { + // DB Operation + t, err := GetDBUtils().CreateObject(c, m, t) + return t, err +} + +func (c *ResourceObjectManager) GetObject(m map[string]string) (module.ControllerObject, error) { + // DB Operation + t, err := GetDBUtils().GetObject(c, m) + return t, err +} + +func (c *ResourceObjectManager) GetObjects(m map[string]string) ([]module.ControllerObject, error) { + // DB Operation + t, err := GetDBUtils().GetObjects(c, m) + return t, err +} + +func (c *ResourceObjectManager) UpdateObject(m map[string]string, t module.ControllerObject) (module.ControllerObject, error) { + // DB Operation + t, err := GetDBUtils().UpdateObject(c, m, t) + return t, err +} + +func (c *ResourceObjectManager) DeleteObject(m map[string]string) error { + // DB Operation + err := GetDBUtils().DeleteObject(c, m) + return err +} diff --git a/central-controller/src/scc/pkg/manager/resutils.go b/central-controller/src/scc/pkg/manager/resutils.go index 2103130..212aba1 100644 --- a/central-controller/src/scc/pkg/manager/resutils.go +++ b/central-controller/src/scc/pkg/manager/resutils.go @@ -17,13 +17,14 @@ 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("/app/app_name/cluster/clusername/", res.name, res.content) - // -> save ("/app/app_name/cluster/clusername/resource/res.name/", res.content) in etcd - // return ("/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("app/app_name/cluster/clusername/", "resource", "order", "{[res.name]}") - // ->save ("/app/app_name/cluster/clusername/resource/instruction/order/", "{[res.name]}") in etcd - // return "/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 ("app/app_name/", app_name) in etcd - // apphandle = "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("app/app_name/", "cluster", clustername) - // -> save ("app/app_name/cluster/clusername/", clustername) in etcd - // return "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 { diff --git a/central-controller/src/scc/pkg/module/connectionobject.go b/central-controller/src/scc/pkg/module/connectionobject.go index 466b3ff..e507967 100644 --- a/central-controller/src/scc/pkg/module/connectionobject.go +++ b/central-controller/src/scc/pkg/module/connectionobject.go @@ -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 } diff --git a/central-controller/src/scc/pkg/module/deviceobject.go b/central-controller/src/scc/pkg/module/deviceobject.go index 53783de..82fc300 100644 --- a/central-controller/src/scc/pkg/module/deviceobject.go +++ b/central-controller/src/scc/pkg/module/deviceobject.go @@ -47,6 +47,7 @@ type DeviceObjectStatus struct { DataIps map[string]string // Status Data Data map[string]string + DelegatedHub string } func (c *DeviceObject) GetMetadata() ObjectMetaData { diff --git a/central-controller/src/scc/pkg/module/hubdeviceobject.go b/central-controller/src/scc/pkg/module/hubdeviceobject.go index 876b45a..3b681bb 100644 --- a/central-controller/src/scc/pkg/module/hubdeviceobject.go +++ b/central-controller/src/scc/pkg/module/hubdeviceobject.go @@ -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 { diff --git a/central-controller/src/scc/pkg/module/hubobject.go b/central-controller/src/scc/pkg/module/hubobject.go index 70d221e..3e44e3d 100644 --- a/central-controller/src/scc/pkg/module/hubobject.go +++ b/central-controller/src/scc/pkg/module/hubobject.go @@ -16,11 +16,6 @@ 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 index 0000000..9b7587d --- /dev/null +++ b/central-controller/src/scc/pkg/module/resourceobject.go @@ -0,0 +1,39 @@ +/* + * 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 module + +// App contains metadata for Apps +type ResourceObject struct { + Metadata ObjectMetaData `json:"metadata"` + Specification ResourceObjectSpec `json:"spec"` +} + +//ResourceObjectSpec contains the parameters +type ResourceObjectSpec struct { + Hash string `json:"hash"` + Ref int `json:"ref"` + ContextId string `json:"cid"` + Status string `json:"status"` +} + +func (c *ResourceObject) GetMetadata() ObjectMetaData { + return c.Metadata +} + +func (c *ResourceObject) GetType() string { + return "Resource" +} \ No newline at end of file diff --git a/central-controller/src/scc/pkg/resource/empty_resource.go b/central-controller/src/scc/pkg/resource/empty_resource.go index 52db254..e6983e9 100644 --- a/central-controller/src/scc/pkg/resource/empty_resource.go +++ b/central-controller/src/scc/pkg/resource/empty_resource.go @@ -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 index 0000000..46784d3 --- /dev/null +++ b/central-controller/src/scc/pkg/resource/firewall_nat_resource.go @@ -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{}) +} diff --git a/central-controller/src/scc/pkg/resource/ipsec_resource.go b/central-controller/src/scc/pkg/resource/ipsec_resource.go index 59cab05..2928429 100644 --- a/central-controller/src/scc/pkg/resource/ipsec_resource.go +++ b/central-controller/src/scc/pkg/resource/ipsec_resource.go @@ -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 + ` diff --git a/central-controller/src/scc/pkg/resource/resourcebuilder.go b/central-controller/src/scc/pkg/resource/resourcebuilder.go index 06abc40..b048555 100644 --- a/central-controller/src/scc/pkg/resource/resourcebuilder.go +++ b/central-controller/src/scc/pkg/resource/resourcebuilder.go @@ -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 index 0000000..cf2794f --- /dev/null +++ b/central-controller/src/scc/pkg/resource/route_resource.go @@ -0,0 +1,58 @@ +/* + * 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 + +type RouteResource struct { + Name string + Destination string + Gateway string + Device string + Table string +} + +func (c *RouteResource) GetName() string { + return c.Name +} + +func (c *RouteResource) GetType() string { + return "Route" +} + +func (c *RouteResource) ToYaml(target string) string { + basic := `apiVersion: ` + SdewanApiVersion + ` +kind: CNFRoute +metadata: + name: ` + c.Name + ` + namespace: default + labels: + sdewanPurpose: ` + SdewanPurpose + ` + targetCluster: ` + target + ` +spec: + dst: ` + c.Destination + ` + dev: "` + c.Device + `" + table: ` + c.Table + + if c.Gateway != "" { + basic += ` + gw: ` + c.Gateway + } + return basic +} + +func init() { + GetResourceBuilder().Register("Route", &RouteResource{}) +}