github.com/tommi2day/gomodules/dblib@v0.0.0-20230217211148-82cdbcf0a79d/tns.go (about) 1 // Package dblib collection of db func 2 package dblib 3 4 import ( 5 log "github.com/sirupsen/logrus" 6 "github.com/tommi2day/gomodules/common" 7 "os" 8 "path/filepath" 9 "regexp" 10 "strings" 11 ) 12 13 type address struct { 14 Host string 15 Port string 16 } 17 18 // TNSEntry structure for holding one entry from tnsnames.ora 19 type TNSEntry struct { 20 Name string 21 Desc string 22 File string 23 Service string 24 Servers []address 25 } 26 27 // TNSEntries Map of tns entries 28 type TNSEntries map[string]TNSEntry 29 30 func checkSkip(line string) (skip bool) { 31 skip = true 32 found := false 33 reEmpty := regexp.MustCompile(`\S`) 34 reComment := regexp.MustCompile(`^#`) 35 found = reEmpty.MatchString(line) 36 if !found { 37 return 38 } 39 found = reComment.MatchString(line) 40 if found { 41 return 42 } 43 skip = false 44 return 45 } 46 47 // GetEntry matches given string to tns entries using with domain part and without 48 func GetEntry(alias string, entries TNSEntries, domain string) (e TNSEntry, ok bool) { 49 match, _ := regexp.MatchString(`^\w+\.`, alias) 50 if len(domain) > 0 { 51 if match { 52 e, ok = entries[strings.ToUpper(alias)] // full qualified 53 } else { 54 e, ok = entries[strings.ToUpper(alias)+"."+strings.ToUpper(domain)] // short alias+domain 55 } 56 return 57 } 58 // no domain, only full match accepted 59 e, ok = entries[strings.ToUpper(alias)] 60 return 61 } 62 63 // GetTnsnames map tnsnames.ora entries to an readable structure 64 func GetTnsnames(filename string, recursiv bool) (TNSEntries, string, error) { 65 var tnsEntries = make(TNSEntries) 66 var err error 67 var domain = "" 68 var content []string 69 var reIfile = regexp.MustCompile(`(?im)^IFILE\s*=\s*(.*)$`) 70 var reNewEntry = regexp.MustCompile(`(?im)^([\w.]+)\s*=(.*)`) 71 var tnsAlias = "" 72 var desc = "" 73 74 // try to find sqlnet ora and read domain 75 tnsDir := filepath.Dir(filename) 76 domain = GetDefaultDomain(tnsDir) 77 78 // change to current tns file 79 wd, _ := os.Getwd() 80 log.Debugf("DEBUG: GetTns use %s, wd=%s", filename, wd) 81 err = common.ChdirToFile(filename) 82 if err != nil { 83 log.Errorf("Cannot chdir to %s", filename) 84 return tnsEntries, domain, err 85 } 86 87 // use basename from filename to read as i am in this directory 88 f := filepath.Base(filename) 89 content, _ = common.ReadFileByLine(f) 90 91 // loop through lines 92 for _, line := range content { 93 if checkSkip(line) { 94 continue 95 } 96 97 // find and load ifiles 98 ifile := reIfile.FindStringSubmatch(line) 99 if len(ifile) > 0 { 100 fn := ifile[1] 101 ifileEntries, err := getIfile(fn, recursiv) 102 if err == nil { 103 for k, v := range ifileEntries { 104 tnsEntries[k] = v 105 } 106 } 107 continue 108 } 109 110 // find new entry 111 newEntry := reNewEntry.FindStringSubmatch(line) 112 i := len(newEntry) 113 if i > 0 { 114 // save previous entry 115 if len(tnsAlias) > 0 && len(desc) > 0 { 116 tnsEntries[tnsAlias] = buildEntry(filename, desc, tnsAlias) 117 } 118 // new entry 119 tnsAlias = strings.ToUpper(newEntry[1]) 120 if i > 2 { 121 desc = newEntry[2] + "\n" 122 } 123 } else { 124 desc += line 125 } 126 } 127 128 // save last entry 129 if len(tnsAlias) > 0 && len(desc) > 0 { 130 tnsEntries[tnsAlias] = buildEntry(filename, desc, tnsAlias) 131 } 132 133 // chdir back 134 _ = os.Chdir(wd) 135 return tnsEntries, domain, err 136 } 137 138 // read ifile recursive 139 func getIfile(filename string, recursiv bool) (entries TNSEntries, err error) { 140 wd, _ := os.Getwd() 141 log.Debugf("read ifile %s, wd=%s", filename, wd) 142 entries, _, err = GetTnsnames(filename, recursiv) 143 return 144 } 145 146 // build map for entry 147 func buildEntry(filename string, desc string, tnsAlias string) TNSEntry { 148 var service = "" 149 reService := regexp.MustCompile(`(?mi)SERVICE_NAME\s*=\s*([\w.]+)`) 150 s := reService.FindStringSubmatch(desc) 151 if len(s) > 1 { 152 service = s[1] 153 } 154 entry := TNSEntry{Name: tnsAlias, Desc: desc, File: filename, Service: service, Servers: getServers(desc)} 155 log.Debugf("found TNS Alias %s", tnsAlias) 156 return entry 157 } 158 159 // extract address part 160 func getServers(tnsDesc string) (servers []address) { 161 re := regexp.MustCompile(`(?m)HOST\s*=\s*([\w.]+)\s*\)\s*\(\s*PORT\s*=\s*(\d+)`) 162 match := re.FindAllStringSubmatch(tnsDesc, -1) 163 for _, a := range match { 164 if len(a) > 1 { 165 host := a[1] 166 port := a[2] 167 servers = append(servers, address{ 168 Host: host, Port: port, 169 }) 170 log.Debugf("parsed Host: %s, Port %s", host, port) 171 } 172 } 173 return 174 } 175 176 // GetDefaultDomain extract names_default_domain from sqlnet.ora 177 func GetDefaultDomain(path string) (domain string) { 178 filename := "sqlnet.ora" 179 if path != "" { 180 filename = path + "/" + filename 181 } 182 content, err := common.ReadFileToString(filename) 183 if err != nil { 184 log.Debugf("Cannot read %s, assume no default domain", filename) 185 return "" 186 } 187 reg := regexp.MustCompile(`(?im)^NAMES.DEFAULT_DOMAIN\s*=\s*([\w.]*)`) 188 result := reg.FindStringSubmatch(content) 189 if len(result) == 0 { 190 log.Debugf("no default domain defined in %s", filename) 191 return "" 192 } 193 domain = result[1] 194 log.Infof("default domain: %s", domain) 195 return domain 196 }