Skip to content

Commit

Permalink
Sync from server repo (814a28b2852)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Spilchen committed May 1, 2024
1 parent 1df66f8 commit 1f30293
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 45 deletions.
7 changes: 4 additions & 3 deletions vclusterops/adapter_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@ type adapterPool struct {
}

var (
poolInstance adapterPool
poolInstance *adapterPool
once sync.Once
)

// return a singleton instance of the AdapterPool
func getPoolInstance(logger vlog.Printer) adapterPool {
func getPoolInstance(logger vlog.Printer) *adapterPool {
/* if once.Do(f) is called multiple times,
* only the first call will invoke f,
* even if f has a different value in each invocation.
* Reference: https://pkg.go.dev/sync#Once
*/
once.Do(func() {
poolInstance = makeAdapterPool(logger)
pool := makeAdapterPool(logger)
poolInstance = &pool
})

return poolInstance
Expand Down
92 changes: 62 additions & 30 deletions vclusterops/fetch_node_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,15 @@ func (vcc VClusterCommands) VFetchNodeState(options *VFetchNodeStateOptions) ([]
return nil, err
}

// this vdb is used to fetch node version
var vdb VCoordinationDatabase
err = vcc.getVDBFromRunningDB(&vdb, &options.DatabaseOptions)
if err != nil {
return vcc.fetchNodeStateFromDownDB(options)
}

// produce list_allnodes instructions
instructions, err := vcc.produceListAllNodesInstructions(options)
instructions, err := vcc.produceListAllNodesInstructions(options, &vdb)
if err != nil {
return nil, fmt.Errorf("fail to produce instructions, %w", err)
}
Expand All @@ -76,6 +83,19 @@ func (vcc VClusterCommands) VFetchNodeState(options *VFetchNodeStateOptions) ([]
runError := clusterOpEngine.run(vcc.Log)
nodeStates := clusterOpEngine.execContext.nodesInfo
if runError == nil {
// fill node version
for i, nodeInfo := range nodeStates {
vnode, ok := vdb.HostNodeMap[nodeInfo.Address]
if ok {
nodeStates[i].Version = vnode.Version
} else {
// we do not let this fail
// but the version for this node will be empty
vcc.Log.PrintWarning("Cannot find host %s in fetched node versions",
nodeInfo.Address)
}
}

return nodeStates, nil
}

Expand All @@ -95,45 +115,50 @@ func (vcc VClusterCommands) VFetchNodeState(options *VFetchNodeStateOptions) ([]
}

if upNodeCount == 0 {
const msg = "Cannot get node information from running database. " +
"Try to get node information by reading catalog editor.\n" +
"The states of the nodes are shown as DOWN because we failed to fetch the node states."
fmt.Println(msg)
vcc.Log.PrintInfo(msg)
return vcc.fetchNodeStateFromDownDB(options)
}

var downNodeStates []NodeInfo
return nodeStates, runError
}

var fetchDatabaseOptions VFetchCoordinationDatabaseOptions
fetchDatabaseOptions.DatabaseOptions = options.DatabaseOptions
fetchDatabaseOptions.readOnly = true
func (vcc VClusterCommands) fetchNodeStateFromDownDB(options *VFetchNodeStateOptions) ([]NodeInfo, error) {
const msg = "Cannot get node information from running database. " +
"Try to get node information by reading catalog editor.\n" +
"The states of the nodes are shown as DOWN because we failed to fetch the node states."
fmt.Println(msg)
vcc.Log.PrintInfo(msg)

vdb, err := vcc.VFetchCoordinationDatabase(&fetchDatabaseOptions)
if err != nil {
return downNodeStates, err
}
var nodeStates []NodeInfo

for _, h := range vdb.HostList {
var nodeInfo NodeInfo
n := vdb.HostNodeMap[h]
nodeInfo.Address = n.Address
nodeInfo.Name = n.Name
nodeInfo.CatalogPath = n.CatalogPath
nodeInfo.Subcluster = n.Subcluster
nodeInfo.IsPrimary = n.IsPrimary
nodeInfo.Version = n.Version
nodeInfo.State = util.NodeDownState
downNodeStates = append(downNodeStates, nodeInfo)
}
var fetchDatabaseOptions VFetchCoordinationDatabaseOptions
fetchDatabaseOptions.DatabaseOptions = options.DatabaseOptions
fetchDatabaseOptions.readOnly = true
vdb, err := vcc.VFetchCoordinationDatabase(&fetchDatabaseOptions)
if err != nil {
return nodeStates, err
}

return downNodeStates, nil
for _, h := range vdb.HostList {
var nodeInfo NodeInfo
n := vdb.HostNodeMap[h]
nodeInfo.Address = n.Address
nodeInfo.Name = n.Name
nodeInfo.CatalogPath = n.CatalogPath
nodeInfo.Subcluster = n.Subcluster
nodeInfo.IsPrimary = n.IsPrimary
nodeInfo.Version = n.Version
nodeInfo.State = util.NodeDownState
nodeStates = append(nodeStates, nodeInfo)
}

return nodeStates, runError
return nodeStates, nil
}

// produceListAllNodesInstructions will build a list of instructions to execute for
// the fetch node state operation.
func (vcc VClusterCommands) produceListAllNodesInstructions(options *VFetchNodeStateOptions) ([]clusterOp, error) {
func (vcc VClusterCommands) produceListAllNodesInstructions(
options *VFetchNodeStateOptions,
vdb *VCoordinationDatabase) ([]clusterOp, error) {
var instructions []clusterOp

// get hosts
Expand All @@ -149,13 +174,20 @@ func (vcc VClusterCommands) produceListAllNodesInstructions(options *VFetchNodeS
}
}

nmaHealthOp := makeNMAHealthOp(options.Hosts)
nmaReadVerticaVersionOp := makeNMAReadVerticaVersionOp(vdb)

httpsCheckNodeStateOp, err := makeHTTPSCheckNodeStateOp(hosts,
usePassword, options.UserName, options.Password)
if err != nil {
return instructions, err
}

instructions = append(instructions, &httpsCheckNodeStateOp)
instructions = append(instructions,
&nmaHealthOp,
&nmaReadVerticaVersionOp,
&httpsCheckNodeStateOp,
)

return instructions, nil
}
6 changes: 3 additions & 3 deletions vclusterops/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ type nodeStateInfo struct {
}

func (node *nodeStateInfo) asNodeInfo() (n NodeInfo, err error) {
n = node.asNodeInfoWoVer()
n = node.asNodeInfoWithoutVer()
// version can be, eg, v24.0.0-<revision> or v23.4.0-<hotfix|date>-<revision> including a hotfix or daily build date
verWithHotfix := 3
verWithoutHotfix := 2
Expand All @@ -126,8 +126,8 @@ func (node *nodeStateInfo) asNodeInfo() (n NodeInfo, err error) {
return
}

// asNodeInfoWoVer will create a NodeInfo with empty Version and Revision
func (node *nodeStateInfo) asNodeInfoWoVer() (n NodeInfo) {
// asNodeInfoWithoutVer will create a NodeInfo with empty Version and Revision
func (node *nodeStateInfo) asNodeInfoWithoutVer() (n NodeInfo) {
n.Address = node.Address
n.Name = node.Name
n.State = node.State
Expand Down
2 changes: 1 addition & 1 deletion vclusterops/http_request_dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

type requestDispatcher struct {
opBase
pool adapterPool
pool *adapterPool
}

func makeHTTPRequestDispatcher(logger vlog.Printer) requestDispatcher {
Expand Down
7 changes: 2 additions & 5 deletions vclusterops/https_check_node_state_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,8 @@ func (op *httpsCheckNodeStateOp) processResult(execContext *opEngineExecContext)

nodesInfo := nodesInfo{}
for _, node := range nodesStates.NodeList {
if n, err := node.asNodeInfo(); err != nil {
op.logger.PrintError("[%s] %s", op.name, err.Error())
} else {
nodesInfo.NodeList = append(nodesInfo.NodeList, n)
}
n := node.asNodeInfoWithoutVer()
nodesInfo.NodeList = append(nodesInfo.NodeList, n)
}
// successful case, write the result into exec context
execContext.nodesInfo = nodesInfo.NodeList
Expand Down
2 changes: 1 addition & 1 deletion vclusterops/https_get_up_nodes_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func (op *httpsGetUpNodesOp) collectUpHosts(nodesStates nodesStateInfo, host str
}
} else if node.State == util.NodeDownState {
// for "DOWN" node, we cannot get its version from https response
n = node.asNodeInfoWoVer()
n = node.asNodeInfoWithoutVer()
scNodes.Add(n)
}
}
Expand Down
20 changes: 18 additions & 2 deletions vclusterops/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,15 @@ func ResolveToAbsPath(path string) (string, error) {

// IP util functions
func IsIPv4(ip string) bool {
return net.ParseIP(ip).To4() != nil
// To4() may not return nil even if the given address is ipv6
// we need to double check whether the ip string contains `:`
return !strings.Contains(ip, ":") && net.ParseIP(ip).To4() != nil
}

func IsIPv6(ip string) bool {
return net.ParseIP(ip).To16() != nil
// To16() may not return nil even if the given address is ipv4
// we need to double check whether the ip string contains `:`
return strings.Contains(ip, ":") && net.ParseIP(ip).To16() != nil
}

func AddressCheck(address string, ipv6 bool) error {
Expand Down Expand Up @@ -283,14 +287,26 @@ func ResolveToOneIP(hostname string, ipv6 bool) (string, error) {
if ipv6 && IsIPv6(hostname) {
return hostname, nil
}

// resolve host name to address
addrs, err := ResolveToIPAddrs(hostname, ipv6)
// contains the case where the hostname cannot be resolved to be IP
if err != nil {
return "", err
}

ipVersion := ipv4Str
if ipv6 {
ipVersion = ipv6Str
}
if len(addrs) == 0 {
return "", fmt.Errorf("cannot resolve %s as %s address", hostname, ipVersion)
}

if len(addrs) > 1 {
return "", fmt.Errorf("%s is resolved to more than one IP addresss: %v", hostname, addrs)
}

return addrs[0], nil
}

Expand Down
7 changes: 7 additions & 0 deletions vclusterops/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ func TestResolveToOneIP(t *testing.T) {
res, err = ResolveToOneIP(hostname, false)
assert.NotNil(t, err)
assert.Equal(t, res, "")

// given IP does not match its IP version
_, err = ResolveToOneIP("192.168.1.101", true)
assert.ErrorContains(t, err, "cannot resolve 192.168.1.101 as IPv6 address")

_, err = ResolveToOneIP("2001:db8::8:800:200c:417a", false)
assert.ErrorContains(t, err, "cannot resolve 2001:db8::8:800:200c:417a as IPv4 address")
}

func TestGetCleanPath(t *testing.T) {
Expand Down

0 comments on commit 1f30293

Please sign in to comment.