diff --git a/vclusterops/cluster_op.go b/vclusterops/cluster_op.go index 2f697f7..8caf0f3 100644 --- a/vclusterops/cluster_op.go +++ b/vclusterops/cluster_op.go @@ -206,6 +206,7 @@ type clusterOp interface { applyTLSOptions(tlsOptions opTLSOptions) error isSkipExecute() bool filterUnreachableHosts(execContext *opEngineExecContext) + filterHostsBySandbox(execContext *opEngineExecContext) } /* Cluster ops basic fields and functions @@ -475,6 +476,29 @@ func (op *opBase) filterUnreachableHosts(execContext *opEngineExecContext) { op.hosts = util.SliceDiff(op.hosts, execContext.unreachableHosts) } +// filterHostsBySandbox selects hosts only in the target sandbox or main cluster +func (op *opBase) filterHostsBySandbox(execContext *opEngineExecContext) { + if execContext.sandbox == util.MainClusterSandbox { + return + } + + // If vdb is given as nil or the vdb is obtained, + // we will not filter hosts by sandbox. + // Instead, we will send requests to all hosts. + if execContext.vdbForSandboxInfo == nil { + return + } + + // filter out hosts that are not in the target sandbox or main cluster + var hostsNotInSandbox []string + for h, vnode := range execContext.vdbForSandboxInfo.HostNodeMap { + if vnode.Sandbox != execContext.sandbox { + hostsNotInSandbox = append(hostsNotInSandbox, h) + } + } + op.hosts = util.SliceDiff(op.hosts, hostsNotInSandbox) +} + /* Sensitive fields in request body */ type sensitiveFields struct { diff --git a/vclusterops/cluster_op_engine.go b/vclusterops/cluster_op_engine.go index cd76e8c..3810d09 100644 --- a/vclusterops/cluster_op_engine.go +++ b/vclusterops/cluster_op_engine.go @@ -18,6 +18,7 @@ package vclusterops import ( "fmt" + "github.com/vertica/vcluster/vclusterops/util" "github.com/vertica/vcluster/vclusterops/vlog" ) @@ -35,7 +36,16 @@ func makeClusterOpEngine(instructions []clusterOp, tlsOptions opTLSOptions) VClu } func (opEngine *VClusterOpEngine) run(logger vlog.Printer) error { + // when vdb is nil or sandbox is not specified, + // the op engine will not filter any hosts to send requests + return opEngine.runInSandbox(logger, nil /*vdb*/, util.MainClusterSandbox) +} + +func (opEngine *VClusterOpEngine) runInSandbox(logger vlog.Printer, + vdb *VCoordinationDatabase, sandbox string) error { execContext := makeOpEngineExecContext(logger) + execContext.vdbForSandboxInfo = vdb + execContext.sandbox = sandbox opEngine.execContext = &execContext return opEngine.runWithExecContext(logger, &execContext) @@ -67,6 +77,7 @@ func (opEngine *VClusterOpEngine) runInstruction( defer op.cleanupSpinner() op.filterUnreachableHosts(execContext) + op.filterHostsBySandbox(execContext) op.logPrepare() err := op.prepare(execContext) diff --git a/vclusterops/cluster_op_engine_context.go b/vclusterops/cluster_op_engine_context.go index 0ad856b..af87bb7 100644 --- a/vclusterops/cluster_op_engine_context.go +++ b/vclusterops/cluster_op_engine_context.go @@ -25,7 +25,7 @@ type opEngineExecContext struct { nodesInfo []NodeInfo scNodesInfo []NodeInfo // a node list contains all nodes in a subcluster - // This field is specifically used for sandboxing + // this field is specifically used for sandboxing // as sandboxing requires all nodes in the subcluster to be sandboxed to be UP. upScInfo map[string]string // map with UP hosts as keys and their subcluster names as values. upHostsToSandboxes map[string]string // map with UP hosts as keys and their corresponding sandbox names as values. @@ -44,6 +44,11 @@ type opEngineExecContext struct { // hosts that have the VCluster server PID file HostsWithVclusterServerPid []string + + // sandbox on which the op engine will run instruction + sandbox string + // this vdb will only be used to get sandbox info of the nodes + vdbForSandboxInfo *VCoordinationDatabase } func makeOpEngineExecContext(logger vlog.Printer) opEngineExecContext { diff --git a/vclusterops/start_node.go b/vclusterops/start_node.go index 0bda007..b08ea4b 100644 --- a/vclusterops/start_node.go +++ b/vclusterops/start_node.go @@ -292,7 +292,7 @@ func (vcc VClusterCommands) VStartNodes(options *VStartNodesOptions) error { clusterOpEngine := makeClusterOpEngine(instructions, options) // Give the instructions to the VClusterOpEngine to run - err = clusterOpEngine.run(vcc.Log) + err = clusterOpEngine.runInSandbox(vcc.Log, &vdb, startNodeInfo.Sandbox) if err != nil { return fmt.Errorf("fail to start node, %w", err) } diff --git a/vclusterops/stop_db.go b/vclusterops/stop_db.go index 80c83f4..3b575b5 100644 --- a/vclusterops/stop_db.go +++ b/vclusterops/stop_db.go @@ -160,7 +160,7 @@ func (vcc VClusterCommands) VStopDatabase(options *VStopDatabaseOptions) error { clusterOpEngine := makeClusterOpEngine(instructions, options) // Give the instructions to the VClusterOpEngine to run - runError := clusterOpEngine.run(vcc.Log) + runError := clusterOpEngine.runInSandbox(vcc.GetLog(), &vdb, options.SandboxName) if runError != nil { return fmt.Errorf("fail to stop database: %w", runError) }