From 79fd24a343f6972a4feaef3d6395b391d828c38f Mon Sep 17 00:00:00 2001 From: dwelch-spike <53876192+dwelch-spike@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:46:39 -0800 Subject: [PATCH] feat: add node roles to node list output vec-433 (#24) * build(deps): update go client to support node roles * feat: vec-433 add node roles to node ls output * ci: test node roles with mixed role cluster --- cmd/writers/nodeList.go | 19 +++- cmd/writers/utils.go | 14 +++ cmd/writers/utils_test.go | 87 +++++++++++++++++++ docker/auth/docker-compose.yml | 2 +- docker/mtls/docker-compose.yml | 2 +- docker/multi-node-LB/docker-compose.yml | 22 +++-- .../docker-compose.yml | 6 +- .../config/aerospike-vector-search-1.yml | 3 + docker/multi-node/docker-compose.yml | 22 +++-- docker/tls/docker-compose.yml | 2 +- docker/vanilla/docker-compose.yml | 2 +- e2e_multi_node_LB_test.go | 8 +- e2e_multi_node_test.go | 8 +- go.mod | 6 +- go.sum | 2 + 15 files changed, 173 insertions(+), 32 deletions(-) create mode 100644 cmd/writers/utils_test.go diff --git a/cmd/writers/nodeList.go b/cmd/writers/nodeList.go index ad9e508..205b076 100644 --- a/cmd/writers/nodeList.go +++ b/cmd/writers/nodeList.go @@ -27,7 +27,17 @@ func NewNodeTableWriter(writer io.Writer, isLB bool, logger *slog.Logger) *NodeT t := NodeTableWriter{NewDefaultWriter(writer), isLB, logger} t.table.SetTitle("Nodes") - t.table.AppendHeader(table.Row{"Node", "Endpoint", "Cluster ID", "Version", "Visible Nodes"}, rowConfigAutoMerge) + t.table.AppendHeader( + table.Row{ + "Node", + "Roles", + "Endpoint", + "Cluster ID", + "Version", + "Visible Nodes", + }, + rowConfigAutoMerge, + ) t.table.SetAutoIndex(true) t.table.SortBy([]table.SortBy{ {Name: "Node", Mode: table.Asc}, @@ -59,6 +69,13 @@ func (itw *NodeTableWriter) AppendNodeRow(node *NodeInfo) { row = append(row, id) } + // If the node is a load balancer, it does not have roles. + if !itw.isLB { + row = append(row, formatRoles(node.About.GetRoles())) + } else { + row = append(row, "N/A") + } + row = append(row, formatEndpoint(node.ConnectedEndpoint)) if node.State != nil { diff --git a/cmd/writers/utils.go b/cmd/writers/utils.go index a04c520..f422595 100644 --- a/cmd/writers/utils.go +++ b/cmd/writers/utils.go @@ -53,6 +53,20 @@ func formatEndpoints(nodeID uint64, nodeEndpoints map[uint64]*protos.ServerEndpo return strings.Join(nodeToEndpointsStr, "\n") } +func formatRoles(roles []protos.NodeRole) []string { + formattedRoles := []string{} + + for _, role := range roles { + formattedRoles = append(formattedRoles, formatRole(role)) + } + + return formattedRoles +} + +func formatRole(role protos.NodeRole) string { + return role.String() +} + func renderTable(t table.Writer, format int) string { if format == 0 { return t.Render() diff --git a/cmd/writers/utils_test.go b/cmd/writers/utils_test.go new file mode 100644 index 0000000..5f3203a --- /dev/null +++ b/cmd/writers/utils_test.go @@ -0,0 +1,87 @@ +package writers + +import ( + "reflect" + "testing" + + "github.com/aerospike/avs-client-go/protos" +) + +func Test_formatRole(t *testing.T) { + type args struct { + role protos.NodeRole + } + tests := []struct { + name string + args args + want string + }{ + { + name: "TestRolePrimary", + args: args{role: protos.NodeRole_INDEX_QUERY}, + want: "INDEX_QUERY", + }, + { + name: "TestRoleSecondary", + args: args{role: protos.NodeRole_INDEX_UPDATE}, + want: "INDEX_UPDATE", + }, + { + name: "TestRoleUnknown", + args: args{role: protos.NodeRole_KV_READ}, + want: "KV_READ", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := formatRole(tt.args.role); got != tt.want { + t.Errorf("formatRole() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_formatRoles(t *testing.T) { + type args struct { + roles []protos.NodeRole + } + tests := []struct { + name string + args args + want []string + }{ + { + name: "TestMultipleRoles", + args: args{ + roles: []protos.NodeRole{ + protos.NodeRole_INDEX_QUERY, + protos.NodeRole_INDEX_UPDATE, + protos.NodeRole_KV_READ, + }, + }, + want: []string{"INDEX_QUERY", "INDEX_UPDATE", "KV_READ"}, + }, + { + name: "TestSingleRole", + args: args{roles: []protos.NodeRole{protos.NodeRole_INDEX_QUERY}}, + want: []string{"INDEX_QUERY"}, + }, + { + name: "TestNoRoles", + args: args{roles: []protos.NodeRole{}}, + want: []string{}, + }, + { + name: "TestNilRoles", + args: args{roles: nil}, + want: []string{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := formatRoles(tt.args.roles); !reflect.DeepEqual(got, tt.want) { + t.Errorf("formatRoles() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/docker/auth/docker-compose.yml b/docker/auth/docker-compose.yml index c8efb33..fd58507 100644 --- a/docker/auth/docker-compose.yml +++ b/docker/auth/docker-compose.yml @@ -16,7 +16,7 @@ services: timeout: 20s retries: 20 avs: - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 depends_on: aerospike: condition: service_healthy diff --git a/docker/mtls/docker-compose.yml b/docker/mtls/docker-compose.yml index c8efb33..fd58507 100644 --- a/docker/mtls/docker-compose.yml +++ b/docker/mtls/docker-compose.yml @@ -16,7 +16,7 @@ services: timeout: 20s retries: 20 avs: - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 depends_on: aerospike: condition: service_healthy diff --git a/docker/multi-node-LB/docker-compose.yml b/docker/multi-node-LB/docker-compose.yml index c897842..5eee5dd 100644 --- a/docker/multi-node-LB/docker-compose.yml +++ b/docker/multi-node-LB/docker-compose.yml @@ -5,7 +5,9 @@ services: # - "3000:3000" volumes: - ./config/aerospike.conf:/opt/aerospike/etc/aerospike/aerospike.conf - - ./config/features.conf:/opt/aerospike/etc/aerospike/features.conf + - type: bind + source: ./config/features.conf + target: /opt/aerospike/etc/aerospike/features.conf command: - "--config-file" - "/opt/aerospike/etc/aerospike/aerospike.conf" @@ -20,10 +22,12 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 volumes: - ./config/aerospike-vector-search-1.yml:/etc/aerospike-vector-search/aerospike-vector-search.yml - - ./config/features.conf:/etc/aerospike-vector-search/features.conf + - type: bind + source: ./config/features.conf + target: /etc/aerospike-vector-search/features.conf healthcheck: test: ["CMD", "curl", "-f", "http://avs-1:5040/manage/rest/v1"] interval: 1s @@ -35,10 +39,12 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 volumes: - ./config/aerospike-vector-search-2.yml:/etc/aerospike-vector-search/aerospike-vector-search.yml - - ./config/features.conf:/etc/aerospike-vector-search/features.conf + - type: bind + source: ./config/features.conf + target: /etc/aerospike-vector-search/features.conf healthcheck: test: ["CMD", "curl", "-f", "http://avs-2:5040/manage/rest/v1"] interval: 1s @@ -50,10 +56,12 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 volumes: - ./config/aerospike-vector-search-3.yml:/etc/aerospike-vector-search/aerospike-vector-search.yml - - ./config/features.conf:/etc/aerospike-vector-search/features.conf + - type: bind + source: ./config/features.conf + target: /etc/aerospike-vector-search/features.conf healthcheck: test: ["CMD", "curl", "-f", "http://avs-3:5040/manage/rest/v1"] interval: 1s diff --git a/docker/multi-node-client-visibility-err/docker-compose.yml b/docker/multi-node-client-visibility-err/docker-compose.yml index e75fc92..c7d7bef 100644 --- a/docker/multi-node-client-visibility-err/docker-compose.yml +++ b/docker/multi-node-client-visibility-err/docker-compose.yml @@ -20,7 +20,7 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 ports: - "10000:10000" volumes: @@ -37,7 +37,7 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 ports: - "10001:10001" volumes: @@ -54,7 +54,7 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 # ports: # - "10002:10002" # This causes the visibility err volumes: diff --git a/docker/multi-node/config/aerospike-vector-search-1.yml b/docker/multi-node/config/aerospike-vector-search-1.yml index b7d34be..4841a8c 100644 --- a/docker/multi-node/config/aerospike-vector-search-1.yml +++ b/docker/multi-node/config/aerospike-vector-search-1.yml @@ -6,6 +6,9 @@ cluster: # Unique identifier for this cluster. cluster-name: multi-node-avs + node-roles: + - INDEX_QUERY + # The Proximus service listening ports, TLS and network interface. service: ports: diff --git a/docker/multi-node/docker-compose.yml b/docker/multi-node/docker-compose.yml index 72c4dec..a3d3de8 100644 --- a/docker/multi-node/docker-compose.yml +++ b/docker/multi-node/docker-compose.yml @@ -5,7 +5,9 @@ services: # - "3000:3000" volumes: - ./config/aerospike.conf:/opt/aerospike/etc/aerospike/aerospike.conf - - ./config/features.conf:/opt/aerospike/etc/aerospike/features.conf + - type: bind + source: ./config/features.conf + target: /opt/aerospike/etc/aerospike/features.conf command: - "--config-file" - "/opt/aerospike/etc/aerospike/aerospike.conf" @@ -20,12 +22,14 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 ports: - "10000:10000" volumes: - ./config/aerospike-vector-search-1.yml:/etc/aerospike-vector-search/aerospike-vector-search.yml - - ./config/features.conf:/etc/aerospike-vector-search/features.conf + - type: bind + source: ./config/features.conf + target: /etc/aerospike-vector-search/features.conf healthcheck: test: ["CMD", "curl", "-f", "http://avs-1:5040/manage/rest/v1"] interval: 5s @@ -37,12 +41,14 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 ports: - "10001:10001" volumes: - ./config/aerospike-vector-search-2.yml:/etc/aerospike-vector-search/aerospike-vector-search.yml - - ./config/features.conf:/etc/aerospike-vector-search/features.conf + - type: bind + source: ./config/features.conf + target: /etc/aerospike-vector-search/features.conf healthcheck: test: ["CMD", "curl", "-f", "http://avs-2:5040/manage/rest/v1"] interval: 5s @@ -54,12 +60,14 @@ services: depends_on: aerospike: condition: service_healthy - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 ports: - "10002:10002" volumes: - ./config/aerospike-vector-search-3.yml:/etc/aerospike-vector-search/aerospike-vector-search.yml - - ./config/features.conf:/etc/aerospike-vector-search/features.conf + - type: bind + source: ./config/features.conf + target: /etc/aerospike-vector-search/features.conf healthcheck: test: ["CMD", "curl", "-f", "http://avs-3:5040/manage/rest/v1"] interval: 5s diff --git a/docker/tls/docker-compose.yml b/docker/tls/docker-compose.yml index c8efb33..fd58507 100644 --- a/docker/tls/docker-compose.yml +++ b/docker/tls/docker-compose.yml @@ -16,7 +16,7 @@ services: timeout: 20s retries: 20 avs: - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 depends_on: aerospike: condition: service_healthy diff --git a/docker/vanilla/docker-compose.yml b/docker/vanilla/docker-compose.yml index c8efb33..fd58507 100644 --- a/docker/vanilla/docker-compose.yml +++ b/docker/vanilla/docker-compose.yml @@ -16,7 +16,7 @@ services: timeout: 20s retries: 20 avs: - image: aerospike/aerospike-vector-search:0.11.1 + image: aerospike/aerospike-vector-search:1.0.0 depends_on: aerospike: condition: service_healthy diff --git a/e2e_multi_node_LB_test.go b/e2e_multi_node_LB_test.go index 1eb12fb..e306dd1 100644 --- a/e2e_multi_node_LB_test.go +++ b/e2e_multi_node_LB_test.go @@ -60,8 +60,8 @@ func (suite *MultiNodeLBCmdTestSuite) TestNodeListCmd() { fmt.Sprintf("node ls --format 1 --no-color --seeds %s", suite.AvsHostPort.String()), true, `Nodes -,Node,Endpoint,Cluster ID,Version,Visible Nodes -1,Seed,localhost:10000,,,"{ +,Node,Roles,Endpoint,Cluster ID,Version,Visible Nodes +1,Seed,[INDEX_QUERY INDEX_UPDATE],localhost:10000,,,"{ 1103823447824: [1.1.1.1:10000] 2207646885648: [2.2.2.2:10000] 3311470323472: [3.3.3.3:10000] @@ -79,8 +79,8 @@ Possible scenarios: fmt.Sprintf("node ls --format 1 --no-color --host %s", suite.AvsHostPort.String()), false, `Nodes -,Node,Endpoint,Cluster ID,Version,Visible Nodes -1,LB,localhost:10000,,,"{ +,Node,Roles,Endpoint,Cluster ID,Version,Visible Nodes +1,LB,N/A,localhost:10000,,,"{ 1103823447824: [1.1.1.1:10000] 2207646885648: [2.2.2.2:10000] 3311470323472: [3.3.3.3:10000] diff --git a/e2e_multi_node_test.go b/e2e_multi_node_test.go index baa1c6a..b1ede6a 100644 --- a/e2e_multi_node_test.go +++ b/e2e_multi_node_test.go @@ -55,16 +55,16 @@ func (suite *MultiNodeCmdTestSuite) TestNodeListCmd() { "node ls with multiple nodes and seeds", fmt.Sprintf("node ls --format 1 --no-color --seeds %s", suite.AvsHostPort.String()), `Nodes -,Node,Endpoint,Cluster ID,Version,Visible Nodes -1,139637976803088,127.0.0.1:10000,,,"{ +,Node,Roles,Endpoint,Cluster ID,Version,Visible Nodes +1,139637976803088,[INDEX_QUERY],127.0.0.1:10000,,,"{ 139637976803089: [127.0.0.1:10001] 139637976803090: [127.0.0.1:10002] }" -2,139637976803089,127.0.0.1:10001,,,"{ +2,139637976803089,[INDEX_QUERY INDEX_UPDATE],127.0.0.1:10001,,,"{ 139637976803088: [127.0.0.1:10000] 139637976803090: [127.0.0.1:10002] }" -3,139637976803090,127.0.0.1:10002,,,"{ +3,139637976803090,[INDEX_QUERY INDEX_UPDATE],127.0.0.1:10002,,,"{ 139637976803088: [127.0.0.1:10000] 139637976803089: [127.0.0.1:10001] }" diff --git a/go.mod b/go.mod index 4f2c6d7..a677594 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,11 @@ module asvec -go 1.22 +go 1.22.0 + +toolchain go1.22.1 require ( - github.com/aerospike/avs-client-go v0.0.0-20241025173655-4553b2b412f8 + github.com/aerospike/avs-client-go v0.0.0-20241202214048-3592b2621dbc github.com/aerospike/tools-common-go v0.0.0-20240927170813-c352c1917359 github.com/jedib0t/go-pretty/v6 v6.5.9 github.com/spf13/cobra v1.8.1 diff --git a/go.sum b/go.sum index 834e295..f28131e 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/aerospike/avs-client-go v0.0.0-20241022175841-0802ad7be5d7 h1:V9MX8Sx github.com/aerospike/avs-client-go v0.0.0-20241022175841-0802ad7be5d7/go.mod h1:gveJAyzXlND0g/lA+R6USRg9UcnGAUtyHzcngWrHSTo= github.com/aerospike/avs-client-go v0.0.0-20241025173655-4553b2b412f8 h1:5awce0R9Sn6W7ywQdoKaNG2zWoG15B0fPed615nUN/o= github.com/aerospike/avs-client-go v0.0.0-20241025173655-4553b2b412f8/go.mod h1:gveJAyzXlND0g/lA+R6USRg9UcnGAUtyHzcngWrHSTo= +github.com/aerospike/avs-client-go v0.0.0-20241202214048-3592b2621dbc h1:bWp4AnJKg96V1hDPoHL1Hacynf9vT0VeJpBr+x+gLgA= +github.com/aerospike/avs-client-go v0.0.0-20241202214048-3592b2621dbc/go.mod h1:gveJAyzXlND0g/lA+R6USRg9UcnGAUtyHzcngWrHSTo= github.com/aerospike/tools-common-go v0.0.0-20240927170813-c352c1917359 h1:NXCigFN6GWJizwJSe7xAp5kTz7ZxdNjpyRxaIp6MkuA= github.com/aerospike/tools-common-go v0.0.0-20240927170813-c352c1917359/go.mod h1:Ig1lRynXx0tXNOY3MdtanTsKz1ifG/2AyDFMXn3RMTc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=