golang net module(LookupSRV) - go

I'm very new to golang, I have some experience with python but not on this level per say. I am creating an application that's called "digall", making it easy for a user to see active dns-records when checking a domain name.
In the application I am using LookupSRV, which I seem to have some issues with:
func srvRecord(query string) {
service := "sipfederationtls"
protocol:= "tcp"
fmt.Printf("\n[+] SRV Record(s)\n")
//srvMap := ["sipfederationtls", "autodiscover", "VLMCS"]
cname, addresses, err := net.LookupSRV(service, protocol, query)
if err != nil {
fmt.Printf("[!] This feature is currently under development, thus not ready yet.\n")
}
fmt.Printf("cname : %s \n", cname)
for i := 0; i < len(addresses); i++ {
fmt.Printf("addrs[%d].Target : %s \n", i, addresses[i].Target)
fmt.Printf("addrs[%d].Port : %d \n", i, addresses[i].Port)
fmt.Printf("addrs[%d].Priority : %d \n", i, addresses[i].Priority)
fmt.Printf("addrs[%d].Weight : %d \n", i, addresses[i].Weight)
}
}
As you can see the variable "service" serves as the prefix of the SRV record. My only problem is that i want to check multiple prefixes of this record, namely "sipfederationtls", "autodiscover" and "VLMCS".
What I am asking is; How to i make this function swift through these prefixes and return the ones that work? (the ones that error out will be handled by err by my fantastic error message)
I am aware that this is a noob question, and like I said I am very new to golang. I would appreciate any tips you guys could give me.
Here is the full source of the application: http://dpaste.com/3X24ZYR
Thank you.

You can't query multiple services at once using LookupSRV method, as you can't use dig for querying several services at once.
You better create a slice of the services' names:
services := [...]string{"service1", "service2", "service3")
And then iterate over it and call LookupSRV for each service:
for _, service := range services {
cname , addrs, err := net.LookupSRV(service, "tcp", "your.domain.name")
// error handlling
}
Also when iterating over the lookup result, it is better to use the range keyword:
for _, record := range addrs {
fmt.Printf("Target: %s:%d\n", record.Target, record.Port)
}

Related

How to use Golang to get my wifi ip address?

func getLocalIP() ([]string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
IPs := make([]string, 0)
for _, a := range addrs {
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
IPs = append(IPs, ipNet.IP.To4().String())
}
}
}
return IPs, nil
}
func TestGetLocalIP() {
addrs, _ := getLocalIP()
for _, a := range addrs {
fmt.Println(a)
}
}
I used this,but it give me a list of ip address.
I just want to get my wifi local address,how to do that?
You need to know at least one of two pieces of information going in:
the name of the correct interface (typically en0 on a Mac, e.g., but YMMV)
the address for your wireless network, including the length of the mask - something like 192.168.0.0/16 or 192.168.0.0/24 is pretty common, but you'll have to figure this out ahead of time.
If you only know the interface name:
ifs, _ := net.Interfaces()
for _, ifi := range ifs {
if ifi.Name == "en0" { // Or whatever other filter you want
addrs, _ := ifi.Addresses()
for _, a := range addrs {
// Filter to get the one you want, typically unicast IP4
}
}
}
Still simpler:
if, _ := net.InterfaceByName("en0")
addrs, _ := if.Addresses()
for _, a := range addrs {
// As before, filter for the address you want
}
If you know the network address for your wireless network
// Loop over interfaces, get addrs, then loop over addresses and get IPs for those that have them
if ip.Mask(net.CIDRMask(16, 32)) == myNetworkAddress {
// The interface you got this IP from is probably your wifi interface
}
Which method to choose
Depending on the interface having a specific name is generally not going to be portable. So while my assumption was that you were just trying to get this working on your own workstation, if this is for something which needs to run across multiple hosts, you may need to start off at least with matching against the correct network address. There are other tricks as well - if you know e.g. that you are going to be running in a server farm in which every host has a NIC from manufacturer XXX, you can look up the MAC address and see if it comes from that manufacturer - you can try this out here. You can use other filters as well, but those are going to be pretty specific to your individual use case.

BigQuery Golang maxResults for Queries

I would like to be able to specify maxResults when using the golang BigQuery library. It isn't clear how to do this, though. I don't see it as an option in the documentation, and I have browsed the source to try to find it but I only see some sporadic usage in seemingly functionality not related to queries. Is there a way to circumvent this issue?
I think there is no implemented method in the SDK for that but after looking a bit, I found this one: request
You could try to execute an HTTP GET specifying the parameters (you can find an example of the use of parameters here: query_parameters)
By default the google API iterators manage page size for you. The RowIterator returns a single row by default, backed internally by fetched pages that rely on the backend to select an appropriate size.
If however you want to specify a fixed max page size, you can use the google.golang.org/api/iterator package to iterate by pages while specifying a specific size. The size, in this case, corresponds to maxResults for BigQuery's query APIs.
See https://github.com/googleapis/google-cloud-go/wiki/Iterator-Guidelines for more general information about advanced iterator usage.
Here's a quick test to demonstrate with the RowIterator in bigquery. It executes a query that returns a row for each day in October, and iterates by page:
func TestQueryPager(t *testing.T) {
ctx := context.Background()
pageSize := 5
client, err := bigquery.NewClient(ctx, "your-project-id here")
if err != nil {
t.Fatal(err)
}
defer client.Close()
q := client.Query("SELECT * FROM UNNEST(GENERATE_DATE_ARRAY('2022-10-01','2022-10-31', INTERVAL 1 DAY)) as d")
it, err := q.Read(ctx)
if err != nil {
t.Fatalf("query failure: %v", err)
}
pager := iterator.NewPager(it, pageSize, "")
var fetchedPages int
for {
var rows [][]bigquery.Value
nextToken, err := pager.NextPage(&rows)
if err != nil {
t.Fatalf("NextPage: %v", err)
}
fetchedPages = fetchedPages + 1
if len(rows) > pageSize {
t.Errorf("page size exceeded, got %d want %d", len(rows), pageSize)
}
t.Logf("(next token %s) page size: %d", nextToken, len(rows))
if nextToken == "" {
break
}
}
wantPages := 7
if fetchedPages != wantPages {
t.Fatalf("fetched %d pages, wanted %d pages", fetchedPages, wantPages)
}
}

Multiple queries to Postgres within the same function

I'm new to Go, so sorry for the silly question in advance!
I'm using Gin framework and want to make multiple queries to the database within the same handler (database/sql + lib/pq)
userIds := []int{}
bookIds := []int{}
var id int
/* Handling first query here */
rows, err := pgClient.Query(getUserIdsQuery)
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
err := rows.Scan(&id)
if err != nil {
return
}
userIds = append(userIds, id)
}
/* Handling second query here */
rows, err = pgClient.Query(getBookIdsQuery)
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
err := rows.Scan(&id)
if err != nil {
return
}
bookIds = append(bookIds, id)
}
I have a couple of questions regarding this code (any improvements and best practices would be appreciated)
Does Go properly handle defer rows.Close() in such a case? I mean I have reassignment of rows variable later down the code, so will compiler track both and properly close at the end of a function?
Is it ok to reuse id shared var or should I redeclare it while iterating within rows.Next() loop?
What's the better approach of having even more queries within one handler? Should I have some kind of Writer that accepts query and slice and populate it with ids retrieved?
Thanks.
I've never worked with go-pg library, and my answer is mostly focused on the other stuff, which are generic, and are not specific to golang or go-pg.
Regardless of the fact that the rows here has the same reference while being shared between 2 queries (so one rows.Close() call would suffice, unless the library has some special implementation), defining two variables is cleaner, like userRows and bookRows.
Although I already said that I have not worked with go-pg, I believe that you wont need to iterate through rows and scan the id for all the rows manually, I believe that the lib has provided some API like this (based on the quick look on the documentations):
userIds := []int{}
err := pgClient.Query(&userIds, "select id from users where ...", args...)
Regarding your second question, it depends on what you mean by "ok". Since your doing some synchronous iteration, I don't think it would result into bugs, but when it comes to coding style, personally, I wouldn't do this.
I think that the best thing to do in your case is this:
// repo layer
func getUserIds(args whatever) ([]int, err) {...}
// these can be exposed, based on your packaging logic
func getBookIds(args whatever) ([]int, err) {...}
// service layer, or wherever you want to aggregate both queries
func getUserAndBookIds() ([]int, []int, err) {
userIds, err := getUserIds(...)
// potential error handling
bookIds, err := getBookIds(...)
// potential error handling
return userIds, bookIds, nil // you have done err handling earlier
}
I think this code is easier to read/maintain. You won't face the variable reassignment and other issues.
You can take a look at the go-pg documentations for more details on how to improve your query.

unstructured.UnstructuredList caused lots of reflect.go trace

I'm trying to use the unstructured.UnstructuredList to reuse come logic for configmap and secret.
However, after adding the ListAndDeployReferredObject, I started to see tons of trace as Starting reflector *unstructured.Unstructured was added to my log file.
Am I doing something odd or I'm missing some setting for using the unstructured.Unstructured?
Thanks in advance.
func (r *ReconcileSubscription) ListAndDeployReferredObject(instance *appv1alpha1.Subscription, gvk schema.GroupVersionKind, refObj referredObject) error {
insName := instance.GetName()
insNs := instance.GetNamespace()
uObjList := &unstructured.UnstructuredList{}
uObjList.SetGroupVersionKind(gvk)
opts := &client.ListOptions{Namespace: insNs}
err := r.Client.List(context.TODO(), uObjList, opts)
if err != nil && !errors.IsNotFound(err) {
klog.Errorf("Failed to list referred objects with error %v ", err)
return err
}
// other logics...
}
I0326 23:05:58.955589 95169 reflector.go:120] Starting reflector *unstructured.Unstructured (10m0s) from pkg/mod/k8s.io/client-go#v0.0.0-20191016111102-bec269661e48/tools/cache/reflector.go:96
...
I0326 23:15:18.718932 95169 reflector.go:158] Listing and watching *unstructured.Unstructured from pkg/mod/k8s.io/client-go#v0.0.0-20191016111102-bec269661e48/tools/cache/reflector.go:96
I figured out these prints are normal, since we are using the dynamic client on our controller for caches

Convert array of strings to field name

Newbie question:
I want to print various variables of a library (is that the correct name? reflect.TypeOf(servers) gives []lib.Server)
I want to do something like this, but this obviously does not work:
servers, err := GetClient().GetServers() //call to external API
serverVariables := []string{}
serverVariables = append(serverVariables, "Name")
serverVariables = append(serverVariables, "IPAddress")
for _, server := range servers {
for _,element := range serverVariables {
fmt.Println(server.element)
}
}
What I already can do is the following (but I want to do it using the above approach):
servers, err := GetClient().GetServers() //call to external API
for _, server := range servers {
fmt.Println(server.Name)
fmt.Println(server.IPAddress)
}
giving the following output:
ServerNameOne
192.168.0.1
ServerNameTwo
192.168.0.2
Reflection is what you probably want to use:
for _, server := range servers {
v := reflect.ValueOf(server)
for _, element := range serverVariables {
fmt.Println(v.FieldByName(element))
}
}
You should also change serverVariables initialization to be serverVariables := []string{}
Playground example: https://play.golang.org/p/s_kzIJ7-B7
It seems to me that you have experience in some dynamic language like Python or JavaScript. Go is compiled and strongly typed. Besides reflection being slower, when using it compiler can't help you with finding basic errors in your code and what is most important you lose type of the accessed variable.
More info on http://blog.golang.org/laws-of-reflection
So I strongly recommend you to keep your current approach:
for _, server := range servers {
fmt.Println(server.Name)
fmt.Println(server.IPAddress)
}

Resources