diff --git a/.gitignore b/.gitignore index 2df65224e347b7d94c61db238220b38118c5a538..0340bd651fee853c7c8fa9e2859e891594ee411b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ gl-codeclimate.json # containerlab clab-gosdn*/ +clab-*/ *.yml.bak dev_env_data/clab/*.yaml.bak diff --git a/applications/rtdt-manager/.gitignore b/applications/rtdt-manager/.gitignore index 97e240260a403059f75e4876461ea51d001f1ab0..3b1e998f8d9eabb808312d46a450162b1aa0e9ee 100644 --- a/applications/rtdt-manager/.gitignore +++ b/applications/rtdt-manager/.gitignore @@ -1,3 +1,4 @@ *.bak *.BAK twin* +tmp/ diff --git a/applications/rtdt-manager/clab-config/clab-config.go b/applications/rtdt-manager/clab-config/clab-config.go index 432fb25cb92a174979987dd02f9dcaced27b0e86..75a401e657f9214b8bd8edcb894a0e8c3aab8211 100644 --- a/applications/rtdt-manager/clab-config/clab-config.go +++ b/applications/rtdt-manager/clab-config/clab-config.go @@ -13,7 +13,6 @@ import ( "gopkg.in/yaml.v3" - "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement" util "code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/util" ) @@ -60,9 +59,10 @@ type Link struct { // from the DB var nodeBlueprints = map[string]Node{ "gnmi-target-switch": { - Kind: "linux", - Image: "registry.code.fbi.h-da.de/danet/gnmi-target/debian:interface-enabled-test", - Binds: []string{"../../../artifacts/ssl/gnmi-target:/etc/gnmi-target/ssl"}, + Kind: "linux", + Image: "gnmi-target-local", + //Image: "registry.code.fbi.h-da.de/danet/gnmi-target/debian:interface-enabled-test", + Binds: []string{"../../../../artifacts/ssl/gnmi-target:/etc/gnmi-target/ssl"}, Cmd: "start --ca_file /etc/gnmi-target/ssl/ca.crt --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key", StartupDelay: 5, }, @@ -71,6 +71,41 @@ var nodeBlueprints = map[string]Node{ }, } +// Function for deep copying clab config struct +func (c *ClabConfig) Copy() *ClabConfig { + newC := &ClabConfig{ + Name: c.Name, + Mgmt: c.Mgmt, + Topology: Topology{ + Nodes: make(map[string]Node), + Links: make([]Link, len(c.Topology.Links)), + }, + } + for name, node := range c.Topology.Nodes { + newNode := Node{ + Kind: node.Kind, + Image: node.Image, + Ports: append([]string{}, node.Ports...), + Cmd: node.Cmd, + MgmtIPv4: node.MgmtIPv4, + Env: make(map[string]string), + Binds: append([]string{}, node.Binds...), + StartupDelay: node.StartupDelay, + Group: node.Group, + } + for envName, env := range node.Env { + newNode.Env[envName] = env + } + newC.Topology.Nodes[name] = newNode + } + for i, link := range c.Topology.Links { + newC.Topology.Links[i] = Link{ + Endpoints: append([]string{}, link.Endpoints...), + } + } + return newC +} + func GetNodeTemplate(kind, ipv4subnet string) *Node { re := regexp.MustCompile("(^\\D+)(\\d)") matches := re.FindStringSubmatch(kind) @@ -90,6 +125,8 @@ func GetNodeTemplate(kind, ipv4subnet string) *Node { fmt.Printf("Error trying to get centos digit: %v\n", err) return nil } + // Alter the ideitifying octet in the ipaddress, not ideal but works for now + // Has to be done this way because sdnconfig doesn't save an address for non-gnmi-targets ipOffset := digit + 17 ipv4subnetSplit := strings.Split(ipv4subnet, ".") ipv4subnetSplit[3] = strconv.Itoa(ipOffset) @@ -136,14 +173,18 @@ func LoadConfig(filename string) (*ClabConfig, error) { func WriteConfig(filename string, config *ClabConfig) error { data, err := yaml.Marshal(config) if err != nil { - return fmt.Errorf("failed to marshal YAML: %w", err) + return fmt.Errorf("Failed to marshal YAML: %w", err) + } + dir := filepath.Dir(filename) + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.MkdirAll(dir, 0700); err != nil { + return fmt.Errorf("failed to create directory %s: %w", dir, err) + } } - err = os.WriteFile(filename, data, 0644) if err != nil { return fmt.Errorf("failed to write file: %w", err) } - return nil } @@ -156,46 +197,30 @@ func incrementPort(port string, offset int) (string, error) { return strconv.Itoa(portNum + offset), nil } -// TODO -// What we get from this relevant for ClabConfig: -// Name, Plugin? TransportOptions (Address, Type), TLS yes/no -// Not for ClabConfig but useful: Pnd, GnmiSubscribepaths, -func (c *ClabConfig) InsertMNE(mnes []*networkelement.ManagedNetworkElement) { - for _, mne := range mnes { - c.Topology.Nodes[mne.Name] = Node{ - MgmtIPv4: mne.TransportAddress, - } - } -} - -// Take a clab yaml config file and derive another clab config from it -func DeriveConfig(clabconfig *ClabConfig, newIPv4Subnet, newIPv6Subnet string, postfix string) (*ClabConfig, error) { +// Take a clab yaml config file and derive another clab config from it (only use to derive base clab) +func DeriveConfig(clabConfig *ClabConfig, newIPv4Subnet, newIPv6Subnet string, clabName string) (*ClabConfig, error) { // Create deep copy - derivedConfig := *clabconfig + derivedConfig := *clabConfig derivedConfig.Topology.Nodes = make(map[string]Node) - derivedConfig.Topology.Links = append([]Link{}, clabconfig.Topology.Links...) // Copy links + derivedConfig.Topology.Links = append([]Link{}, clabConfig.Topology.Links...) // Copy links portOffset := 5 // TODO set dynamically in some way - derivedConfig.Name = fmt.Sprintf("%s-%s", clabconfig.Name, postfix) + derivedConfig.Name = fmt.Sprintf("gosdn_%s", clabName) + derivedConfig.Mgmt.Network = fmt.Sprintf("gosdn-%s-net", clabName) subnetParts := strings.Split(newIPv4Subnet, ".") derivedConfig.Mgmt.IPv4Subnet = newIPv4Subnet derivedConfig.Mgmt.IPv6Subnet = newIPv6Subnet - derivedConfig.Mgmt.Network = fmt.Sprintf("%s-%s", clabconfig.Name, postfix) // Adjust all nodes - for name, node := range clabconfig.Topology.Nodes { + for name, node := range clabConfig.Topology.Nodes { splitIPv4 := strings.Split(node.MgmtIPv4, ".") splitIPv4[0], splitIPv4[1], splitIPv4[2] = subnetParts[0], subnetParts[1], subnetParts[2] node.MgmtIPv4 = strings.Join(splitIPv4, ".") - if strings.HasPrefix(name, "gosdn") { - node.Cmd = "--config /app/configs/containerlab-gosdn-twin.toml" - //node.Binds = []string{"../../../applications/rtdt-manager/data/ssl/gosdn:/app/ssl"} - } - // - // //use separate ssl folders, testing - // if strings.HasPrefix(name, "gnmi-target") { - // node.Binds = []string{"../../../applications/rtdt-manager/data/ssl/gnmi-target:/etc/gnmi-target/ssl"} + // if strings.HasPrefix(name, "gosdn") { + // pluginRegistryAddress := fmt.Sprintf("clab-%s-plugin-registry:55057", clabConfig.Name) + // dbAddress := fmt.Sprintf("mongodb://root:example@clab-%s-mongodb:27017", clabConfig.Name) + // node.Cmd = fmt.Sprintf("%s --plugin-registry %s -d %s", node.Cmd, pluginRegistryAddress, dbAddress) // } // Ports: host side needs to be incremented or there will be conflicts // for now just use 5 as increment @@ -224,18 +249,6 @@ func DeriveConfig(clabconfig *ClabConfig, newIPv4Subnet, newIPv6Subnet string, p } derivedConfig.Topology.Nodes[name] = node } - - // Update Links so they reference the correct nodes - // for i, link := range clabconfig.Topology.Links { - // for j, endpoint := range link.Endpoints { - // parts := strings.Split(endpoint, ":") - // if len(parts) != 2 { - // return nil, fmt.Errorf("invalid link endpoint: %s", endpoint) - // } - // clabconfig.Topology.Links[i].Endpoints[j] = strings.Join(parts, ":") - // } - // } - return &derivedConfig, nil } diff --git a/applications/rtdt-manager/data/base-clab.yaml b/applications/rtdt-manager/data/base-clab.yaml index ca733ff57cef7ad9ba1534cd6d0c536e293bac7e..8e051a11fd4637588849eb4047504c16a0d398cf 100644 --- a/applications/rtdt-manager/data/base-clab.yaml +++ b/applications/rtdt-manager/data/base-clab.yaml @@ -20,7 +20,7 @@ topology: - 55055:55055 - 8080:8080 - 40000:40000 - cmd: --config /app/configs/containerlab-gosdn.toml + cmd: --config /app/configs/containerlab-gosdn.toml --plugin-registry clab-gosdn_realnet-plugin-registry:55057 -d mongodb://root:example@clab-realnet_gosdn-mongodb:27017 mgmt-ipv4: 172.100.0.5 env: GOSDN_ADMIN_PASSWORD: TestPassword diff --git a/applications/rtdt-manager/data/realnet-deploy-clab.yaml b/applications/rtdt-manager/data/realnet-deploy-clab.yaml index 29ac6e68025919cee25192d923de860110ec8a55..a13d662a493481b97fc836b4087065c6761aaf64 100644 --- a/applications/rtdt-manager/data/realnet-deploy-clab.yaml +++ b/applications/rtdt-manager/data/realnet-deploy-clab.yaml @@ -18,7 +18,7 @@ topology: group: server gnmi-target-switch0: kind: linux - image: registry.code.fbi.h-da.de/danet/gnmi-target/debian:interface-enabled-test + image: gnmi-target-local cmd: start --ca_file /etc/gnmi-target/ssl/ca.crt --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key mgmt-ipv4: 172.100.0.11 binds: @@ -26,7 +26,7 @@ topology: startup-delay: 5 gnmi-target-switch1: kind: linux - image: registry.code.fbi.h-da.de/danet/gnmi-target/debian:interface-enabled-test + image: gnmi-target-local cmd: start --ca_file /etc/gnmi-target/ssl/ca.crt --cert /etc/gnmi-target/ssl/certs/gnmi-target-selfsigned.crt --key /etc/gnmi-target/ssl/private/gnmi-target-selfsigned.key mgmt-ipv4: 172.100.0.12 binds: @@ -39,7 +39,7 @@ topology: - 55055:55055 - 8080:8080 - 40000:40000 - cmd: --config /app/configs/containerlab-gosdn.toml --plugin-registry clab-gosdn_realnet-plugin-registry:55057 -d mongodb://root:example@clab-gosdn_realnet-mongodb:27017 + cmd: --config /app/configs/containerlab-gosdn.toml --plugin-registry clab-gosdn_realnet-plugin-registry:55057 -d mongodb://root:example@172.100.0.13:27017 mgmt-ipv4: 172.100.0.5 env: GOSDN_ADMIN_PASSWORD: TestPassword diff --git a/applications/rtdt-manager/main.go b/applications/rtdt-manager/main.go index df792348b185281792cadc0beb2cec04b6bcf88c..4bee9cc7ba850f2ef999391952d02920f680fc10 100644 --- a/applications/rtdt-manager/main.go +++ b/applications/rtdt-manager/main.go @@ -93,7 +93,7 @@ func main() { } if withTwin { - rtdtMan.LaunchTwin("172.101.0.0/16", "2001:db9::/64", "TEST-TWIN") + rtdtMan.LaunchTwin("172.101.0.0/16", "2001:db9::/64", "test-twin") } if err := rtdtMan.Run(); err != nil { fmt.Println("Program exited with errors: %w", err) diff --git a/applications/rtdt-manager/rtdt-manager/rtdt-manager.go b/applications/rtdt-manager/rtdt-manager/rtdt-manager.go index 37136d8c33ab51578398012fb5219008642c7dbc..ae5d2f77bdc269a678b7754030b68ad770f799a1 100644 --- a/applications/rtdt-manager/rtdt-manager/rtdt-manager.go +++ b/applications/rtdt-manager/rtdt-manager/rtdt-manager.go @@ -10,14 +10,10 @@ import ( "sync" "time" - "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/networkelement" "code.fbi.h-da.de/danet/gosdn/application-framework/event" - "code.fbi.h-da.de/danet/gosdn/application-framework/registration" clabconfig "code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/clab-config" - rtdt_topology "code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/rtdt-topology" "code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/sdnconfig" - "code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/util" "code.fbi.h-da.de/danet/gosdn/applications/rtdt-manager/venv" ) @@ -49,7 +45,7 @@ func (r *RtdtManager) LaunchRealnetVEnv(realnetName string, sdnConfig *sdnconfig var realnetClabFName string // Generate a clabconfig file based on the base config and sdnconfig - realnetClab, err := r.ProduceClabConfig(realnetName, r.baseClabConfig, sdnConfig) + realnetClab, err := r.ProduceClabConfig(realnetName, sdnConfig, r.baseClabConfig.Copy()) if err != nil { return fmt.Errorf("Error in LaunchRealnet(): %w", err) } @@ -59,6 +55,7 @@ func (r *RtdtManager) LaunchRealnetVEnv(realnetName string, sdnConfig *sdnconfig if err != nil { return fmt.Errorf("Error in LaunchRealnet() %w", err) } + realnetClabPath += "/tmp" realnetClabFName = filepath.Join(realnetClabPath, realnetName+"-deploy-clab.yaml") err = clabconfig.WriteConfig(realnetClabFName, realnetClab) if err != nil { @@ -78,87 +75,50 @@ func (r *RtdtManager) LaunchRealnetVEnv(realnetName string, sdnConfig *sdnconfig if r.realnet == nil { return fmt.Errorf("Error in LaunchRealnet: Couldn't deploy VEnv") } - //TODO: REPLACE THIS WITH ApplyConfiguration() ??? - // Create the devices based on sdn config file - // err = r.realnet.CreateDevices() - // if err != nil { - // fmt.Printf("Error: Couldn't create devices!") - // return err - // } - // // Apply the topology based on links in the sdn config file: - // err = r.realnet.UploadTopology() - // if err != nil { - // fmt.Printf("Error occured while trying to upload r.realnet topology to DB: %v\n", err) - // return err - // } - // return fmt.Errorf("--------------------ONLY RUN UNTIL HERE----------------------------") - - // This doesn't work for some reason.. err = r.realnet.ApplyConfiguration(sdnConfig) if err != nil { fmt.Printf("Failed to apply configuration: %v\n", err) } - return fmt.Errorf("--------------------ONLY RUN UNTIL HERE----------------------------") - - // Now setup the just-created environment - // Need to: - // - Upload managed network elements - err = r.realnet.DeriveTopologyFromClabData() - if err != nil { - fmt.Printf("Error occured while trying to construct topology in r.realnet: %v\n", err) - return err - } - return nil - err = r.realnet.UploadClabConfig() - if err != nil { - fmt.Printf("Error: Couldnt upload clab config: %v\n", err) - return err - } - // err = r.realnet.RetrieveClabConfig() - // if err != nil { - // fmt.Printf("Error: Couldn't retrieve clab config: %v\n", err) - // return err - // } - return nil } -func (r *RtdtManager) ProduceClabConfig(clabName string, c *clabconfig.ClabConfig, sdnConfig *sdnconfig.SdnConfig) (*clabconfig.ClabConfig, error) { - var clabConfig *clabconfig.ClabConfig +// takes a prepared sdnconfig to produce a clabConfig struct based on it +func (r *RtdtManager) ProduceClabConfig(name string, sdnConfig *sdnconfig.SdnConfig, baseClab *clabconfig.ClabConfig) (*clabconfig.ClabConfig, error) { + // Test abort conditions if sdnConfig == nil { return nil, fmt.Errorf("Can't produce clab config without loading sdnconfig\n") } - // clabConfig can be nil, but wouldn't be very useful without base gosdn environment - if c != nil { - clabConfig = c - for nodeName, node := range clabConfig.Topology.Nodes { - // database and plugin-registry need to be loaded dynamically based on generated name - if strings.HasPrefix(nodeName, "gosdn") { - pluginRegistryAddress := fmt.Sprintf("clab-%s-plugin-registry:55057", clabConfig.Name) - dbAddress := fmt.Sprintf("mongodb://root:example@clab-%s-mongodb:27017", clabConfig.Name) - newCmd := fmt.Sprintf("%s --plugin-registry %s -d %s", node.Cmd, pluginRegistryAddress, dbAddress) - node.Cmd = newCmd - clabConfig.Topology.Nodes[nodeName] = node - fmt.Println("node.Cmd is now:", node.Cmd) - } - } - } else { - return nil, fmt.Errorf("No base clabconfig set\n") - } if sdnConfig.Nodes == nil { return nil, fmt.Errorf("sdnconfig exists, but Nodes is nil") } + // First get all the node of base gosdn environment (rabbitmq, mongodb etc.) + clabConfig := baseClab + pluginRegistryAddress := clabConfig.Topology.Nodes["plugin-registry"].MgmtIPv4 + mongodbAddress := clabConfig.Topology.Nodes["mongodb"].MgmtIPv4 + // Replace the nodes on the basis of base config + // var NewNodes map[string]clabconfig.Node + for nodename, node := range clabConfig.Topology.Nodes { + // newName := fmt.Sprintf("%s-%s", nodename, name) + if strings.HasPrefix(nodename, "gosdn") { + node.Binds = []string{"../../../../artifacts/ssl/gosdn:/app/ssl"} + pluginRegistryAddress := fmt.Sprintf("%s:55057", pluginRegistryAddress) + dbAddress := fmt.Sprintf("mongodb://root:example@%s:27017", mongodbAddress) + node.Cmd = fmt.Sprintf("%s --plugin-registry %s -d %s", node.Cmd, pluginRegistryAddress, dbAddress) + clabConfig.Topology.Nodes[nodename] = node + } + } + // Create the entries in the clabconfig struct for _, node := range sdnConfig.Nodes { var clabNode *clabconfig.Node - clabNode = clabconfig.GetNodeTemplate(node.Name, c.Mgmt.IPv4Subnet) + clabNode = clabconfig.GetNodeTemplate(node.Name, clabConfig.Mgmt.IPv4Subnet) if clabNode == nil { return nil, fmt.Errorf("No template exists for node %s", node.Name) } mne := sdnConfig.GetMneByID(node.ID) if mne != nil { ipv4 := strings.Split(mne.TransportAddress, ":") - clabNode.MgmtIPv4 = ipv4[0] // Doesn't work wor centos hosts + clabNode.MgmtIPv4 = ipv4[0] // Doesn't work for non-gnmi-targets } else { fmt.Printf("ProduceClabConfig(): Warning: No MNE entry for node: %s\n", node.Name) } @@ -183,50 +143,46 @@ func (r *RtdtManager) ProduceClabConfig(clabName string, c *clabconfig.ClabConfi // - Use that config to call "containerlab deploy" // Launch a second gosdn instance which will manage the virtual network func (r *RtdtManager) LaunchTwin(twinSubnetIPv4, twinSubnetIPv6, twinName string) error { - var derivedConfig *clabconfig.ClabConfig - var twinClabConfig *clabconfig.ClabConfig var clabConfigPath string var err error - var topo *rtdt_topology.Topology - conn := r.realnet.GetConn() - - topo = r.realnet.GetTopology() - if topo == nil { - return fmt.Errorf("Error: Couldn't get topology since it hasn't been retrieved from DB yet") + var prefixLength int + prefixRegex := regexp.MustCompile("/(\\d+)$") + prefixMatch := prefixRegex.FindStringSubmatch(twinSubnetIPv4) + if len(prefixMatch) > 1 { + prefixLength, err = strconv.Atoi(prefixMatch[1]) + if err != nil { + return err + } + } else { + return fmt.Errorf("Couldn't extract prefix length from ipv4 subnet address") } // First add the base config's nodes - twinClabConfig = r.baseClabConfig - // Now retrieve the nodes (gnmi-targets and hosts + topology) via MNE Api - mneServiceRealnet := networkelement.NewNetworkElementServiceClient(conn) - getRequest := &networkelement.GetAllRequest{ - Timestamp: util.Now(), - Pid: r.realnet.GetPnd().Id, + TwinSdnConfig := sdnconfig.SdnConfig{} + // Get the up-to-date sdnconfig from realnet DB + err = TwinSdnConfig.RetrieveSdnConfig(r.realnet.GetPnd().String(), *r.realnet.GetAuth()) + if err != nil { + return fmt.Errorf("LaunchTwin Error: %v\n", err) } - mneCtx := r.realnet.GetAuth().CreateContextWithAuthorization() - getAllResponse, err := mneServiceRealnet.GetAll(mneCtx, getRequest) - elements := getAllResponse.GetMne() - // These now need to go into the new VEnv's clabData so clab yaml config can be created - if len(elements) > 0 { - twinClabConfig.InsertMNE(elements) + // Transpose the retrieved SdnConfig structs + TwinSdnConfig.Transpose(twinName, twinSubnetIPv4, twinSubnetIPv6, prefixLength) + fmt.Println("TwinSdnConfig:") + fmt.Println(TwinSdnConfig) + // produce the twin clab configuration based on the transposed sdnconfig and derived clab + baseClabConfig, err := clabconfig.DeriveConfig(r.baseClabConfig.Copy(), twinSubnetIPv4, twinSubnetIPv6, twinName) + twinClabConfig, err := r.ProduceClabConfig(twinName, &TwinSdnConfig, baseClabConfig) + if err != nil { + return err } - // Also get topology from db - // TODO: Maybe update the topology first before retrieving it? - // reminder: Topology might not include all targets? TODO: Check UploadTopology - rtdt_topology.NewTopology().RetrieveTopology(r.realnet.GetPnd().Id, r.realnet.GetAuth()) - - // Could pass topo, clabconfig and elements into this + // Construct filepath for derived clab yaml // Get the basic containerlab config with gosdn, mongodb, rabbitmq clabConfigPath, err = clabconfig.ClabConfigPath() if err != nil { return err } - if derivedConfig, err = clabconfig.DeriveConfig(twinClabConfig, twinSubnetIPv4, twinSubnetIPv6, twinName); err != nil { - return fmt.Errorf("Failed to derive config for twin: %w", err) - } - // Construct filepath for derived clab yaml - twinClabFName := filepath.Join(clabConfigPath, "twin-clab.yaml") - if err = clabconfig.WriteConfig(twinClabFName, derivedConfig); err != nil { + clabConfigPath += "/tmp" + twinClabFName := filepath.Join(clabConfigPath, twinName+"-clab.yaml") + if err = clabconfig.WriteConfig(twinClabFName, twinClabConfig); err != nil { return fmt.Errorf("Failed to write modified twin clab config to disk: %w", err) } diff --git a/applications/rtdt-manager/sdnconfig/sdnconfig.go b/applications/rtdt-manager/sdnconfig/sdnconfig.go index 23c70e86c6bdcd942488b04ab189c19ed77c8b78..89032c9ec2e3d5c54ced8e885f5e13963e0bac01 100644 --- a/applications/rtdt-manager/sdnconfig/sdnconfig.go +++ b/applications/rtdt-manager/sdnconfig/sdnconfig.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" configPb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/configurationmanagement" @@ -120,6 +121,7 @@ func (s *SdnConfig) LoadSdnConfig(configFilename string) error { return fmt.Errorf("Error in LoadSdnConfig(): %w", err) } + // Output // jsonData, err := json.MarshalIndent(s, "", " ") // if err != nil { // return fmt.Errorf("Error marshalling struct to JSON: %w", err) @@ -130,6 +132,52 @@ func (s *SdnConfig) LoadSdnConfig(configFilename string) error { return nil } +// Transpose an sdnconfig struct networkElements +// takes name of network, address range in ipv4 and ipv6 (e.g. 172.101.0.0) and ipv4 prefix for network +// Limitations: +// - No differing prefix lengths between realnet, twin, +// - No prefix lengths other than 8, 16, 24 (cidr) +func (s *SdnConfig) Transpose(name, addressIpv4, addressIpv6 string, ipv4PrefixLength int) { + ipv4Parts := strings.Split(addressIpv4, ".") + for i := range s.Nodes { + s.Nodes[i].Name += fmt.Sprintf("-%s", name) + } + for i, mne := range s.NetworkElements { + HostIpv4Parts := strings.Split(s.NetworkElements[i].TransportAddress, ".") + var NewIpv4 string + switch ipv4PrefixLength { + case 8: + NewIpv4 = fmt.Sprintf("%s.%s.%s.%s", ipv4Parts[0], HostIpv4Parts[1], HostIpv4Parts[2], HostIpv4Parts[3]) + case 16: + NewIpv4 = fmt.Sprintf("%s.%s.%s.%s", ipv4Parts[0], ipv4Parts[1], HostIpv4Parts[2], HostIpv4Parts[3]) + case 24: + NewIpv4 = fmt.Sprintf("%s.%s.%s.%s", ipv4Parts[0], ipv4Parts[1], ipv4Parts[2], HostIpv4Parts[3]) + default: + fmt.Printf("Error: unsupported ipv4 prefix length\n") + + } + s.NetworkElements[i].Name += fmt.Sprintf("-%s", name) + // TransportAddress has form 172.100.0.5:7030 + s.NetworkElements[i].TransportAddress = NewIpv4 + s.NetworkElements[i].Model = s.transposeModelIpv4(mne.Model, mne.TransportAddress, addressIpv6, ipv4PrefixLength) + } + for i := range s.Links { + s.Links[i].SourceNode.Name += fmt.Sprintf("-%s", name) + s.Links[i].TargetNode.Name += fmt.Sprintf("-%s", name) + } +} + +func (s *SdnConfig) transposeModelIpv4(model, ipv4, oldIpv4 string, ipv4PrefixLength int) string { + ipv4Parts := strings.Split(ipv4, ".") + OldIpv4Parts := strings.Split(oldIpv4, ".") + networkPortionLength := ipv4PrefixLength / 8 + oldNetworkPortion := strings.Join(OldIpv4Parts[:networkPortionLength-1], ".") + newNetworkPortion := strings.Join(ipv4Parts[:networkPortionLength-1], ".") + strings.ReplaceAll(model, oldNetworkPortion, newNetworkPortion) + + return model +} + func (s *SdnConfig) RetrieveSdnConfig(pndId string, auth rtdt_auth.RtdtAuth) error { var err error conn := auth.GetConn() diff --git a/applications/rtdt-manager/venv/venv.go b/applications/rtdt-manager/venv/venv.go index 1e9edbf042fb1150f3eb2942407ba50b556c87e7..516725614fdf1774ffa3b90ae4e52a1c47a869da 100644 --- a/applications/rtdt-manager/venv/venv.go +++ b/applications/rtdt-manager/venv/venv.go @@ -29,7 +29,6 @@ import ( "github.com/openconfig/ygot/ygot" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "gopkg.in/yaml.v3" ) type VEnv struct { @@ -81,8 +80,8 @@ func NewVEnv(name, clabFilename, user, pass string, wg *sync.WaitGroup, sdnConfi } } - fmt.Printf("[%s] - Sleep for 10 seconds to give containers time to settle..\n", name) - time.Sleep(time.Second * 10) + fmt.Printf("[%s] - Sleep for 15 seconds to give containers time to settle..\n", name) + time.Sleep(time.Second * 15) // Now log into gosdn physical network dialOption := grpc.WithTransportCredentials(insecure.NewCredentials()) gosdnconn, err := grpc.NewClient(gosdnAddress, dialOption, grpc.WithDefaultCallOptions()) @@ -124,6 +123,7 @@ func NewVEnv(name, clabFilename, user, pass string, wg *sync.WaitGroup, sdnConfi } } +// Upload a sdnconfig .json file to the DB func (v *VEnv) ApplyConfiguration(sdnConfig *sdnconfig.SdnConfig) error { v.sdnConfig = sdnConfig sdnConfigParsed, err := json.Marshal(v.sdnConfig) @@ -351,88 +351,6 @@ func (v *VEnv) UploadTopology() error { return nil } -// What this does: Upload the nodes that make up the gosdn environment -// via the gosdn configuration service to the db (applies to db, message broker, etc.) -// This is probably not the intended use for the configuration interface? -// TODO Delete! Wrong approach -func (v *VEnv) UploadClabConfig() error { - if v.clabData == nil { - return fmt.Errorf("Can't upload clabconfig when it hasn't been loaded yet (is nil pointer)") - } - var clabToUpload = *v.clabData - for nodename, node := range v.clabData.Topology.Nodes { - if !strings.Contains(nodename, "gosdn") && - !strings.Contains(nodename, "mongodb") && - !strings.Contains(nodename, "rabbitmq") && - !strings.Contains(nodename, "plugin-registry") { - fmt.Println("Removing node:", node) - delete(clabToUpload.Topology.Nodes, nodename) - } - } - clabToUpload.Topology.Links = nil - - clabConfig, err := yaml.Marshal(clabToUpload) - if err != nil { - return fmt.Errorf("Encountered error marshalling clabConfig: %w", err) - } - var jsonData interface{} - if err := yaml.Unmarshal(clabConfig, &jsonData); err != nil { - return fmt.Errorf("failed to unmarshal YAML to JSON: %w", err) - } - jsonBytes, err := json.MarshalIndent(jsonData, "", " ") - if err != nil { - return fmt.Errorf("Failed to marshal JSON: %w", err) - } - - req := &configPb.ImportSDNConfigRequest{ - Timestamp: util.Now(), - Pid: v.pnd.GetId(), // TODO: check if this can be nil - SdnConfigData: string(jsonBytes), - } - conn := v.auth.GetConn() - configService := configPb.NewConfigurationManagementServiceClient(conn) - ctx := v.auth.CreateContextWithAuthorization() - configResponse, err := configService.ImportSDNConfig(ctx, req) - if err != nil { - return err - } - fmt.Println("Successfully uploaded clab config:", configResponse.String()) - return nil -} - -// TODO This doesn't really work this way.. -func (v *VEnv) RetrieveClabConfig() error { - ctx := v.auth.CreateContextWithAuthorization() - conn := v.auth.GetConn() - configService := configPb.NewConfigurationManagementServiceClient(conn) - - req := &configPb.ExportSDNConfigRequest{ - Timestamp: util.Now(), - Pid: v.pnd.GetId(), - } - - configResponse, err := configService.ExportSDNConfig(ctx, req) - if err != nil { - return fmt.Errorf("Failed retrieving config clab data: %w", err) - } - var jsonData map[string]interface{} - err = json.Unmarshal([]byte(configResponse.SdnConfigData), &jsonData) - if err != nil { - return fmt.Errorf("Failed to unmarshal SDN config data: %w", err) - } - // Pretty-print the JSON data - formattedJSON, err := json.MarshalIndent(jsonData, "", " ") - if err != nil { - return fmt.Errorf("failed to format JSON data: %w", err) - } - - fmt.Println("Retrieved SDN Config Data:") - fmt.Println(string(formattedJSON)) // Print the formatted JSON - - return nil - -} - func getTypedValue(value string) *gnmi.TypedValue { if boolVal, err := strconv.ParseBool(value); err == nil { return &gnmi.TypedValue{Value: &gnmi.TypedValue_BoolVal{BoolVal: boolVal}} diff --git a/controller/interfaces/networkelement/networkElement.go b/controller/interfaces/networkelement/networkElement.go index 39b7ae9c3297a68c1f3ff22dc3637255d8c3ea04..3433e4350c1ed07dc50c8dd0d3e25fd7058742d8 100644 --- a/controller/interfaces/networkelement/networkElement.go +++ b/controller/interfaces/networkelement/networkElement.go @@ -89,7 +89,7 @@ func EnsureIntendedConfigurationIsAppliedOnNetworkElement(mne NetworkElement) er } fmt.Println("Made it here 1") - req.Update = []*gpb.Update{{ + req.Replace = []*gpb.Update{{ Path: path, Val: &gpb.TypedValue{ Value: &gpb.TypedValue_JsonIetfVal{JsonIetfVal: []byte(model)}, diff --git a/controller/northbound/server/configurationmanagement.go b/controller/northbound/server/configurationmanagement.go index 8b93acc6c6c6be762ef1536fc8a162cce6287222..71dd2e2df3316de6c5b166c7cfbc12c2c9c42570 100644 --- a/controller/northbound/server/configurationmanagement.go +++ b/controller/northbound/server/configurationmanagement.go @@ -109,7 +109,6 @@ func (c ConfigurationManagementServer) ExportSDNConfig(ctx context.Context, requ ReattachConfig: *plug.GetClient().ReattachConfig(), } sdnConfig.Plugins = append(sdnConfig.Plugins, loadedPlugin) - } sdnConfig.Nodes, err = c.nodeService.GetAll() @@ -334,6 +333,7 @@ func (c ConfigurationManagementServer) createNetworkElements(sdnConfig *loadedSD // TODO: change TransportOption - type is not needed; this should // be removed as soon as we remove the csbi device type Type: spb.Type_TYPE_OPENCONFIG, + Tls: inputNetworkElement.TransportTLS, } plugin, err := c.pluginService.RequestPlugin(uuid.MustParse(inputNetworkElement.Plugin))