Repository: nats-io/nats-server (go)

Issue:
Add Server Name to Leafz Monitoring Endpoint
## Feature Request
In the monitoring endpoint, for /Leafz, add serverName attribute of the Leafnode that connected. 

#### Use Case:
The IP doesn't give us all of the information that we need to uniquely identify which of the many Leafnodes that are connecting to the core nats server. For example, we have connections coming outside of our network that get DNAT to a different IP that the original leafnode server was using. Also, deploying within a K8S environment uses the internal K8S IP and tracking it down can be difficult.

#### Proposed Change:
Change the LeafInfo struct to include Server Name of the Leaf node and then within the loop that is building the LeafNodes call ln.leaf.remoteServer for the cluster name.

#### Who Benefits From The Change(s)?
Anyone that uses K8S or bridges networks together where DNAT is involved. 

#### Alternative Approaches
Build out a better way of showing the entire nats / leafnodes topology.


Pull request:
Update LEAFZ to include leafnode server/connection name
resolves #3921 

 - [ ] Documentation added (if applicable)
 - [x] Tests added
 - [x] Branch rebased on top of current main (`git pull --rebase origin main`)
 - [x] Changes squashed to a single commit (described [here](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html))
 - [ ] Build is green in Travis CI
 - [x] You have certified that the contribution is your original work and that you license the work to the project under the [Apache 2 license](https://github.com/nats-io/nats-server/blob/main/LICENSE)

### Changes proposed in this pull request:

Adds `Name` field to `LEAFZ` info for incoming and outgoing leafnode connections. This should allow observability tools to more easily identify leaf nodes without having to require SYS accounts set up for each leaf node connection.


Patch:
diff --git a/server/leafnode.go b/server/leafnode.go
index 6be7657e..7f2e8dcf 100644
--- a/server/leafnode.go
+++ b/server/leafnode.go
@@ -888,7 +888,13 @@ func (s *Server) createLeafNode(conn net.Conn, rURL *url.URL, remote *leafNodeCf
 	}
 	now := time.Now().UTC()
 
-	c := &client{srv: s, nc: conn, kind: LEAF, opts: defaultOpts, mpay: maxPay, msubs: maxSubs, start: now, last: now}
+	var clientOpts = ClientOpts{
+		Name:     opts.ServerName,
+		Verbose:  defaultOpts.Verbose,
+		Pedantic: defaultOpts.Pedantic,
+		Echo:     defaultOpts.Echo,
+	}
+	c := &client{srv: s, nc: conn, kind: LEAF, opts: clientOpts, mpay: maxPay, msubs: maxSubs, start: now, last: now}
 	// Do not update the smap here, we need to do it in initLeafNodeSmapAndSendSubs
 	c.leaf = &leaf{}
 
diff --git a/server/monitor.go b/server/monitor.go
index b19ffb2c..d4365f60 100644
--- a/server/monitor.go
+++ b/server/monitor.go
@@ -2094,6 +2094,7 @@ type LeafzOptions struct {
 
 // LeafInfo has detailed information on each remote leafnode connection.
 type LeafInfo struct {
+	Name     string   `json:"name"`
 	Account  string   `json:"account"`
 	IP       string   `json:"ip"`
 	Port     int      `json:"port"`
@@ -2133,6 +2134,7 @@ func (s *Server) Leafz(opts *LeafzOptions) (*Leafz, error) {
 		for _, ln := range lconns {
 			ln.mu.Lock()
 			lni := &LeafInfo{
+				Name:     ln.opts.Name,
 				Account:  ln.acc.Name,
 				IP:       ln.host,
 				Port:     int(ln.port),


Test patch:
diff --git a/server/monitor_test.go b/server/monitor_test.go
index 67fedb5c..8096ce22 100644
--- a/server/monitor_test.go
+++ b/server/monitor_test.go
@@ -3707,11 +3707,13 @@ func TestMonitorLeafz(t *testing.T) {
 	}
 	acc1, mycreds1 := createAcc(t)
 	acc2, mycreds2 := createAcc(t)
+	leafName := "my-leaf-node"
 
 	content = `
 		port: -1
 		http: "127.0.0.1:-1"
 		ping_interval = 1
+		server_name: %s
 		accounts {
 			%s {
 				users [
@@ -3740,6 +3742,7 @@ func TestMonitorLeafz(t *testing.T) {
 		}
 		`
 	config := fmt.Sprintf(content,
+		leafName,
 		acc1.Name, acc2.Name,
 		acc1.Name, ob.LeafNode.Port, mycreds1,
 		acc2.Name, ob.LeafNode.Port, mycreds2)
@@ -3814,6 +3817,9 @@ func TestMonitorLeafz(t *testing.T) {
 			} else {
 				t.Fatalf("Expected account to be %q or %q, got %q", acc1.Name, acc2.Name, ln.Account)
 			}
+			if ln.Name != leafName {
+				t.Fatalf("Expected name to be %q, got %q", leafName, ln.Name)
+			}
 			if ln.RTT == "" {
 				t.Fatalf("RTT not tracked?")
 			}
@@ -3902,6 +3908,9 @@ func TestMonitorLeafz(t *testing.T) {
 			} else {
 				t.Fatalf("Expected account to be %q or %q, got %q", acc1.Name, acc2.Name, ln.Account)
 			}
+			if ln.Name != leafName {
+				t.Fatalf("Expected name to be %q, got %q", leafName, ln.Name)
+			}
 			if ln.RTT == "" {
 				t.Fatalf("RTT not tracked?")
 			}