diff --git a/vclusterops/https_get_up_nodes_op.go b/vclusterops/https_get_up_nodes_op.go index 1aca1a8..cdaec9d 100644 --- a/vclusterops/https_get_up_nodes_op.go +++ b/vclusterops/https_get_up_nodes_op.go @@ -382,12 +382,15 @@ func (op *httpsGetUpNodesOp) collectUnsandboxingHosts(nodesStates nodesStateInfo mainNodeFound := false sandboxNodeFound := false for _, node := range nodesStates.NodeList { - if node.State == util.NodeUpState { + // We can only send unsandbox commands from nodes that are in the UP or UNKNOWN state (in a sandbox) + // If the node is in any other states, it cannot unsandbox or cannot receive https requests + if node.State == util.NodeUpState || node.State == util.NodeUnknownState { // A sandbox could consist of multiple subclusters. // We need to run unsandbox command on the other subcluster node in the same sandbox // Find a node from same sandbox but different subcluster, if exists if node.Sandbox == op.sandbox && node.Subcluster != op.scName { sandboxInfo[node.Address] = node.Sandbox + sandboxNodeFound = true } // Get one main cluster host if node.Sandbox == "" && !mainNodeFound { diff --git a/vclusterops/https_poll_node_state_indirect_op.go b/vclusterops/https_poll_node_state_indirect_op.go index 26962f5..39203c5 100644 --- a/vclusterops/https_poll_node_state_indirect_op.go +++ b/vclusterops/https_poll_node_state_indirect_op.go @@ -24,6 +24,11 @@ import ( "github.com/vertica/vcluster/vclusterops/util" ) +// httpsPollNodeStateIndirectOp allows polling for the state of nodes when those nodes certainly +// or possibly cannot be polled directly for their state. For example, compute nodes, or nodes of +// unknown type. Instead of calling the nodes endpoint directly on each host for info about only +// that node, it calls the nodes endpoint for all nodes on a separate slice of hosts (e.g. primary +// UP nodes in the same sandbox) which should know the states of all the nodes being checked. type httpsPollNodeStateIndirectOp struct { opBase opHTTPSBase @@ -224,7 +229,7 @@ func (op *httpsPollNodeStateIndirectOp) shouldStopPolling() (bool, error) { return true, err } - // check which nodes have COMPUTE status + // check which nodes have desired state, e.g. COMPUTE, UP, etc. upNodeCount := 0 for _, nodeInfo := range nodesInformation.NodeList { _, ok := op.checkedHostsToState[nodeInfo.Address] diff --git a/vclusterops/https_unsandbox_subcluster_op.go b/vclusterops/https_unsandbox_subcluster_op.go index 7c7c969..11538bf 100644 --- a/vclusterops/https_unsandbox_subcluster_op.go +++ b/vclusterops/https_unsandbox_subcluster_op.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" + mapset "github.com/deckarep/golang-set/v2" "github.com/vertica/vcluster/vclusterops/util" ) @@ -75,21 +76,24 @@ func (op *httpsUnsandboxingOp) setupRequestBody() error { } func (op *httpsUnsandboxingOp) prepare(execContext *opEngineExecContext) error { + sandboxes := mapset.NewSet[string]() var mainHost string if len(execContext.upHostsToSandboxes) == 0 { return fmt.Errorf(`[%s] Cannot find any up hosts in OpEngineExecContext`, op.name) } - // use an UP host in main cluster to execute the https post request + // use an UP host in main cluster and UP host in separate sc in same sandbox to execute the https post request for h, sb := range execContext.upHostsToSandboxes { + if !sandboxes.Contains(sb) { + op.hosts = append(op.hosts, h) + sandboxes.Add(sb) + } if sb == "" { mainHost = h - break } } if mainHost == "" { return fmt.Errorf(`[%s] Cannot find any up hosts of main cluster in OpEngineExecContext`, op.name) } - op.hosts = []string{mainHost} err := op.setupRequestBody() if err != nil { return err