Skip to content

Commit

Permalink
Sync from server repo (03b7e5a706d)
Browse files Browse the repository at this point in the history
  • Loading branch information
releng committed Oct 8, 2024
1 parent 6a33c1f commit 80e04d7
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 19 deletions.
1 change: 1 addition & 0 deletions commands/cluster_command_launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ const (
stopNodeFlag = "stop-hosts"
reIPFileFlag = "re-ip-file"
removeNodeFlag = "remove"
removeUnboundNodesFlag = "remove-unbound-nodes"
startNodeFlag = "start"
startHostFlag = "start-hosts"
)
Expand Down
11 changes: 10 additions & 1 deletion commands/cmd_remove_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Examples:
newCmd.setLocalFlags(cmd)

// require hosts to remove
markFlagsRequired(cmd, removeNodeFlag)
markFlagsOneRequired(cmd, []string{removeNodeFlag, removeUnboundNodesFlag})

return cmd
}
Expand All @@ -78,6 +78,15 @@ func (c *CmdRemoveNode) setLocalFlags(cmd *cobra.Command) {
[]string{},
"A comma-separated list of hosts to remove from the database",
)
cmd.Flags().StringSliceVar(
&c.removeNodeOptions.UnboundNodesToRemove,
removeUnboundNodesFlag,
[]string{},
"A comma-separated list of unbound secondary node names to remove from the database. "+
"If users revived their database to primary nodes only, the not revived secondary nodes become unbound. "+
"Unbound nodes do not have associated IPs in the catalog. "+
"Use this option only if there are unbound nodes to remove.",
)
}

func (c *CmdRemoveNode) Parse(inputArgv []string, logger vlog.Printer) error {
Expand Down
58 changes: 53 additions & 5 deletions vclusterops/remove_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"errors"
"fmt"

mapset "github.com/deckarep/golang-set/v2"
"github.com/vertica/vcluster/vclusterops/util"
"github.com/vertica/vcluster/vclusterops/vlog"
)
Expand All @@ -27,10 +28,11 @@ import (
// the database.
type VRemoveNodeOptions struct {
DatabaseOptions
HostsToRemove []string // Hosts to remove from database
Initiator string // A primary up host that will be used to execute remove_node operations.
ForceDelete bool // whether force delete directories
IsSubcluster bool // is removing all nodes for a subcluster
HostsToRemove []string // Hosts to remove from database
UnboundNodesToRemove []string // Unbound nodes to remove from database
Initiator string // A primary up host that will be used to execute remove_node operations.
ForceDelete bool // whether force delete directories
IsSubcluster bool // is removing all nodes for a subcluster
// Names of the nodes that need to have active subscription. The user of vclusterOps needs
// to make sure the provided values are correct. This option will be used when some nodes
// cannot join the main cluster so we will only check the node subscription state for the nodes
Expand Down Expand Up @@ -88,7 +90,7 @@ func (options *VRemoveNodeOptions) validateParseOptions(logger vlog.Printer) err
func (options *VRemoveNodeOptions) analyzeOptions() (err error) {
options.HostsToRemove, err = util.ResolveRawHostsToAddresses(options.HostsToRemove, options.IPv6)
if err != nil {
return err
return fmt.Errorf("cannot resolve the provided host addresses, detail: %w", err)
}

// we analyze host names when it is set in user input, otherwise we use hosts in yaml config
Expand Down Expand Up @@ -147,6 +149,14 @@ func (vcc VClusterCommands) VRemoveNode(options *VRemoveNodeOptions) (VCoordinat
var hostsNotInCatalog []string
options.HostsToRemove, hostsNotInCatalog = vdb.containNodes(options.HostsToRemove)

// remove unbound nodes from catalog
if len(options.UnboundNodesToRemove) > 0 {
err = vcc.removeUnboundNodesInCatalog(options, &vdb)
if err != nil {
return vdb, fmt.Errorf("failed to remove unbound nodes from catalog, details: %w", err)
}
}

vdb, err = vcc.removeNodesInCatalog(options, &vdb)
if err != nil || len(hostsNotInCatalog) == 0 {
return vdb, err
Expand All @@ -155,6 +165,42 @@ func (vcc VClusterCommands) VRemoveNode(options *VRemoveNodeOptions) (VCoordinat
return vcc.handleRemoveNodeForHostsNotInCatalog(&vdb, options, hostsNotInCatalog)
}

// removeUnboundNodesInCatalog removes unbound nodes from the catalog
func (vcc VClusterCommands) removeUnboundNodesInCatalog(options *VRemoveNodeOptions,
vdb *VCoordinationDatabase) error {
vlog.DisplayColorInfo("Removing unbound nodes from catalog")

var instructions []clusterOp
var initiatorHost []string

usePassword := options.usePassword
userName := options.UserName
password := options.Password
initiatorHost = append(initiatorHost, options.Initiator)

unboundNodesInCatalog := mapset.NewSet[string]()
for _, vnode := range vdb.UnboundNodes {
unboundNodesInCatalog.Add(vnode.Name)
}

for _, unboundNode := range options.UnboundNodesToRemove {
if !unboundNodesInCatalog.Contains(unboundNode) {
return fmt.Errorf("%q is not an unbound node or does not exist in catalog", unboundNode)
}

httpsDropNodeOp, err := makeHTTPSDropNodeOp(unboundNode, initiatorHost,
usePassword, userName, password,
true /*cascade*/)
if err != nil {
return err
}
instructions = append(instructions, &httpsDropNodeOp)
}

clusterOpEngine := makeClusterOpEngine(instructions, options)
return clusterOpEngine.run(vcc.Log)
}

// removeNodesInCatalog will perform the steps to remove nodes. The node list in
// options.HostsToRemove has already been verified that each node is in the
// catalog.
Expand All @@ -165,6 +211,8 @@ func (vcc VClusterCommands) removeNodesInCatalog(options *VRemoveNodeOptions, vd
}
vcc.Log.V(1).Info("validated input hosts", "HostsToRemove", options.HostsToRemove)

vlog.DisplayColorInfo("Removing bound nodes from catalog")

err := options.setInitiator(vdb.PrimaryUpNodes)
if err != nil {
return *vdb, err
Expand Down
37 changes: 24 additions & 13 deletions vclusterops/remove_subcluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (vcc VClusterCommands) VRemoveSubcluster(removeScOpt *VRemoveScOptions) (VC

// pre-check: should not remove the default subcluster
vcc.PrintInfo("Performing remove_subcluster pre-checks")
hostsToRemove, err := vcc.removeScPreCheck(&vdb, removeScOpt)
hostsToRemove, unboundNodesToRemove, err := vcc.removeScPreCheck(&vdb, removeScOpt)
if err != nil {
return vdb, err
}
Expand All @@ -183,7 +183,7 @@ func (vcc VClusterCommands) VRemoveSubcluster(removeScOpt *VRemoveScOptions) (VC
// the number of nodes to remove is greater than zero
var needRemoveNodes bool
vcc.Log.V(1).Info("Nodes to be removed: %+v", hostsToRemove)
if len(hostsToRemove) == 0 {
if len(hostsToRemove) == 0 && len(unboundNodesToRemove) == 0 {
vcc.Log.PrintInfo("no node found in subcluster %s",
removeScOpt.SCName)
needRemoveNodes = false
Expand All @@ -196,12 +196,18 @@ func (vcc VClusterCommands) VRemoveSubcluster(removeScOpt *VRemoveScOptions) (VC
removeNodeOpt := VRemoveNodeOptionsFactory()
removeNodeOpt.DatabaseOptions = removeScOpt.DatabaseOptions
removeNodeOpt.HostsToRemove = hostsToRemove
removeNodeOpt.UnboundNodesToRemove = unboundNodesToRemove
removeNodeOpt.ForceDelete = removeScOpt.ForceDelete
removeNodeOpt.IsSubcluster = true
removeNodeOpt.NodesToPullSubs = removeScOpt.NodesToPullSubs

vcc.Log.PrintInfo("Removing nodes %q from subcluster %s",
hostsToRemove, removeScOpt.SCName)
if len(unboundNodesToRemove) > 0 {
vcc.Log.PrintInfo("Removing unbound nodes %q from subcluster %s",
unboundNodesToRemove, removeScOpt.SCName)
}

vdb, err = vcc.VRemoveNode(&removeNodeOpt)
if err != nil {
return vdb, err
Expand Down Expand Up @@ -233,26 +239,27 @@ func (e *removeDefaultSubclusterError) Error() string {
// for a successful remove_node:
// - Get cluster and nodes info (check if the target DB is Eon and get to-be-removed node list)
// - Get the subcluster info (check if the target sc exists and if it is the default sc)
func (vcc VClusterCommands) removeScPreCheck(vdb *VCoordinationDatabase, options *VRemoveScOptions) ([]string, error) {
var hostsToRemove []string
func (vcc VClusterCommands) removeScPreCheck(
vdb *VCoordinationDatabase,
options *VRemoveScOptions) (hostsToRemove, unboundNodesToRemove []string, err error) {
const preCheckErrMsg = "while performing remove_subcluster pre-checks"

// get cluster and nodes info
err := vcc.getVDBFromRunningDB(vdb, &options.DatabaseOptions)
err = vcc.getVDBFromRunningDB(vdb, &options.DatabaseOptions)
if err != nil {
return hostsToRemove, err
return hostsToRemove, unboundNodesToRemove, err
}

// remove_subcluster only works with Eon database
if !vdb.IsEon {
// info from running db confirms that the db is not Eon
return hostsToRemove, fmt.Errorf(`cannot remove subcluster from an enterprise database '%s'`,
return hostsToRemove, unboundNodesToRemove, fmt.Errorf(`cannot remove subcluster from an enterprise database '%s'`,
options.DBName)
}

err = options.completeVDBSetting(vdb)
if err != nil {
return hostsToRemove, err
return hostsToRemove, unboundNodesToRemove, err
}

// get default subcluster
Expand All @@ -262,7 +269,7 @@ func (vcc VClusterCommands) removeScPreCheck(vdb *VCoordinationDatabase, options
options.SCName,
false /*do not ignore not found*/, RemoveSubclusterCmd)
if err != nil {
return hostsToRemove, fmt.Errorf("fail to get default subcluster %s, details: %w",
return hostsToRemove, unboundNodesToRemove, fmt.Errorf("fail to get default subcluster %s, details: %w",
preCheckErrMsg, err)
}

Expand All @@ -278,14 +285,14 @@ func (vcc VClusterCommands) removeScPreCheck(vdb *VCoordinationDatabase, options
if strings.Contains(err.Error(), "does not exist in the database") {
vcc.Log.PrintError("fail to get subclusters' information %s, %v", preCheckErrMsg, err)
rfcErr := rfc7807.New(rfc7807.SubclusterNotFound).WithHost(options.Hosts[0])
return hostsToRemove, rfcErr
return hostsToRemove, unboundNodesToRemove, rfcErr
}
return hostsToRemove, err
return hostsToRemove, unboundNodesToRemove, err
}

// the default subcluster should not be removed
if options.SCName == clusterOpEngine.execContext.defaultSCName {
return hostsToRemove, &removeDefaultSubclusterError{Name: options.SCName}
return hostsToRemove, unboundNodesToRemove, &removeDefaultSubclusterError{Name: options.SCName}
}

// get nodes of the to-be-removed subcluster
Expand All @@ -295,7 +302,11 @@ func (vcc VClusterCommands) removeScPreCheck(vdb *VCoordinationDatabase, options
}
}

return hostsToRemove, nil
for _, vnode := range vdb.UnboundNodes {
unboundNodesToRemove = append(unboundNodesToRemove, vnode.Name)
}

return hostsToRemove, unboundNodesToRemove, nil
}

// completeVDBSetting sets some VCoordinationDatabase fields we cannot get yet
Expand Down

0 comments on commit 80e04d7

Please sign in to comment.