Skip to content

Commit

Permalink
Sync from server repo (d9f18cf4984)
Browse files Browse the repository at this point in the history
  • Loading branch information
releng committed Nov 22, 2024
1 parent cf50448 commit 41a8011
Show file tree
Hide file tree
Showing 16 changed files with 508 additions and 24 deletions.
4 changes: 4 additions & 0 deletions commands/cluster_command_launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ const (
configParamKey = "configParam"
configParamFileFlag = "config-param-file"
configParamFileKey = "configParamFile"
licenseFileFlag = "license-file"
licenseHostFlag = "license-host"
logPathFlag = "log-path"
logPathKey = "logPath"
keyFileFlag = "key-file"
Expand Down Expand Up @@ -245,6 +247,7 @@ const (
createArchiveCmd = "create_archive"
saveRestorePointsSubCmd = "save_restore_point"
getDrainingStatusSubCmd = "get_draining_status"
upgradeLicenseCmd = "upgrade_license"
)

// cmdGlobals holds global variables shared by multiple
Expand Down Expand Up @@ -630,6 +633,7 @@ func constructCmds() []*cobra.Command {
makeCmdPromoteSandbox(),
makeCmdCreateArchive(),
makeCmdSaveRestorePoint(),
makeCmdUpgradeLicense(),
}
}

Expand Down
142 changes: 142 additions & 0 deletions commands/cmd_upgrade_license.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
(c) Copyright [2023-2024] Open Text.
Licensed under the Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package commands

import (
"github.com/spf13/cobra"
"github.com/vertica/vcluster/vclusterops"
"github.com/vertica/vcluster/vclusterops/vlog"
)

/* CmdUpgradeLicense
*
* Parses arguments to upgrade-license and calls
* the high-level function for upgrade-license.
*
* Implements ClusterCommand interface
*/

type CmdUpgradeLicense struct {
CmdBase
upgradeLicenseOptions *vclusterops.VUpgradeLicenseOptions
}

func makeCmdUpgradeLicense() *cobra.Command {
newCmd := &CmdUpgradeLicense{}
opt := vclusterops.VUpgradeLicenseFactory()
newCmd.upgradeLicenseOptions = &opt

cmd := makeBasicCobraCmd(
newCmd,
upgradeLicenseCmd,
"Upgrade license.",
`Upgrade license.
Examples:
# Upgrade license
vcluster upgrade_license --license-file LICENSE_FILE --license-host HOST_OF_LICENSE_FILE
# Upgrade license with connecting using database password
vcluster upgrade_license --license-file LICENSE_FILE --license-host HOST_OF_LICENSE_FILE --password "PASSWORD"
`,
[]string{dbNameFlag, configFlag, passwordFlag,
hostsFlag, ipv6Flag},
)

// local flags
newCmd.setLocalFlags(cmd)

// require license file path
markFlagsRequired(cmd, licenseFileFlag)
markFlagsRequired(cmd, licenseHostFlag)

return cmd
}

// setLocalFlags will set the local flags the command has
func (c *CmdUpgradeLicense) setLocalFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(
&c.upgradeLicenseOptions.LicenseFilePath,
licenseFileFlag,
"",
"Absolute path of the license file.",
)
cmd.Flags().StringVar(
&c.upgradeLicenseOptions.LicenseHost,
licenseHostFlag,
"",
"The host the license file located on.",
)
}

func (c *CmdUpgradeLicense) Parse(inputArgv []string, logger vlog.Printer) error {
c.argv = inputArgv
logger.LogArgParse(&c.argv)

// for some options, we do not want to use their default values,
// if they are not provided in cli,
// reset the value of those options to nil
c.ResetUserInputOptions(&c.upgradeLicenseOptions.DatabaseOptions)

return c.validateParse(logger)
}

func (c *CmdUpgradeLicense) validateParse(logger vlog.Printer) error {
logger.Info("Called validateParse()")

err := c.ValidateParseBaseOptions(&c.upgradeLicenseOptions.DatabaseOptions)
if err != nil {
return err
}

if !c.usePassword() {
err = c.getCertFilesFromCertPaths(&c.upgradeLicenseOptions.DatabaseOptions)
if err != nil {
return err
}
}
err = c.setDBPassword(&c.upgradeLicenseOptions.DatabaseOptions)
if err != nil {
return err
}

return nil
}

func (c *CmdUpgradeLicense) Analyze(logger vlog.Printer) error {
logger.Info("Called method Analyze()")
return nil
}

func (c *CmdUpgradeLicense) Run(vcc vclusterops.ClusterCommands) error {
vcc.LogInfo("Called method Run()")

options := c.upgradeLicenseOptions

err := vcc.VUpgradeLicense(options)
if err != nil {
vcc.LogError(err, "failed to upgrade license", "license file", options.LicenseFilePath)
return err
}

vcc.DisplayInfo("Successfully upgraded license: %s", options.LicenseFilePath)
return nil
}

// SetDatabaseOptions will assign a vclusterops.DatabaseOptions instance to the one in CmdUpgradeLicense
func (c *CmdUpgradeLicense) SetDatabaseOptions(opt *vclusterops.DatabaseOptions) {
c.upgradeLicenseOptions.DatabaseOptions = *opt
}
1 change: 1 addition & 0 deletions vclusterops/cluster_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ type ClusterCommands interface {
VStopNode(options *VStopNodeOptions) error
VStopSubcluster(options *VStopSubclusterOptions) error
VUnsandbox(options *VUnsandboxOptions) error
VUpgradeLicense(options *VUpgradeLicenseOptions) error
}

type VClusterCommandsLogger struct {
Expand Down
1 change: 1 addition & 0 deletions vclusterops/cluster_op_engine_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type opEngineExecContext struct {
networkProfiles map[string]networkProfile
nmaVDatabase nmaVDatabase
upHosts []string // a sorted host list that contains all up nodes
computeHosts []string // a sorted host list that contains all up (COMPUTE) compute nodes
nodesInfo []NodeInfo
scNodesInfo []NodeInfo // a node list contains all nodes in a subcluster

Expand Down
2 changes: 2 additions & 0 deletions vclusterops/cmd_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
RemoveNodeSyncCat
CreateArchiveCmd
PollSubclusterStateCmd
UpgradeLicenseCmd
)

var cmdStringMap = map[CmdType]string{
Expand Down Expand Up @@ -84,6 +85,7 @@ var cmdStringMap = map[CmdType]string{
RemoveNodeSyncCat: "remove_node_sync_cat",
CreateArchiveCmd: "create_archive",
PollSubclusterStateCmd: "poll_subcluster_state",
UpgradeLicenseCmd: "upgrade_license",
}

func (cmd CmdType) CmdString() string {
Expand Down
14 changes: 11 additions & 3 deletions vclusterops/coordinator_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,16 @@ func (vdb *VCoordinationDatabase) addNode(vnode *VCoordinationNode) error {
// in all clusters (main and sandboxes)
func (vdb *VCoordinationDatabase) addHosts(hosts []string, scName string,
existingHostNodeMap vHostNodeMap) error {
totalHostCount := len(hosts) + len(existingHostNodeMap)
totalHostCount := len(hosts) + len(existingHostNodeMap) + len(vdb.UnboundNodes)
nodeNameToHost := genNodeNameToHostMap(existingHostNodeMap)
// The GenVNodeName(...) function below will generate node names based on nodeNameToHost and totalHostCount.
// If a name already exists, it won't be re-generated.
// In this case, we need to add unbound node names into this map too.
// Otherwise, the new nodes will reuse the existing unbound node names, then make a clash later on.
for _, vnode := range vdb.UnboundNodes {
nodeNameToHost[vnode.Name] = vnode.Address
}

for _, host := range hosts {
vNode := makeVCoordinationNode()
name, ok := util.GenVNodeName(nodeNameToHost, vdb.Name, totalHostCount)
Expand Down Expand Up @@ -339,13 +347,13 @@ func (vdb *VCoordinationDatabase) filterUpHostlist(inputHosts []string, sandbox
// host address not found in vdb, skip it
continue
}
if vnode.Sandbox == "" && vnode.State == util.NodeUpState {
if vnode.Sandbox == util.MainClusterSandbox && vnode.State == util.NodeUpState {
clusterHosts = append(clusterHosts, vnode.Address)
} else if vnode.Sandbox == sandbox && vnode.State == util.NodeUpState {
upSandboxHosts = append(upSandboxHosts, vnode.Address)
}
}
if sandbox == "" {
if sandbox == util.MainClusterSandbox {
return clusterHosts
}
return upSandboxHosts
Expand Down
3 changes: 3 additions & 0 deletions vclusterops/fetch_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ func (vcc VClusterCommands) VFetchCoordinationDatabase(options *VFetchCoordinati
}

for h, n := range nmaVDB.HostNodeMap {
if h == util.UnboundedIPv4 || h == util.UnboundedIPv6 {
continue
}
vnode, ok := vdb.HostNodeMap[h]
if !ok {
return vdb, fmt.Errorf("host %s is not found in the vdb object", h)
Expand Down
6 changes: 6 additions & 0 deletions vclusterops/https_check_subcluster_sandbox_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package vclusterops
import (
"errors"
"fmt"

"github.com/vertica/vcluster/vclusterops/util"
)

type httpsCheckSubclusterSandboxOp struct {
Expand Down Expand Up @@ -60,6 +62,10 @@ func (op *httpsCheckSubclusterSandboxOp) setupClusterHTTPRequest(hosts []string)
}

func (op *httpsCheckSubclusterSandboxOp) prepare(execContext *opEngineExecContext) error {
if execContext.computeHosts != nil {
op.hosts = util.SliceDiff(op.hosts, execContext.computeHosts)
}

execContext.dispatcher.setup(op.hosts)

return op.setupClusterHTTPRequest(op.hosts)
Expand Down
2 changes: 1 addition & 1 deletion vclusterops/https_create_archive_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (op *httpsCreateArchiveOp) processResult(_ *opEngineExecContext) error {
var allErrs error

// every host needs to have a successful result, otherwise we fail this op
// because we want depot created successfully on all hosts
// because we want archives to be created
for host, result := range op.clusterHTTPRequest.ResultCollection {
op.logResponse(host, result)

Expand Down
30 changes: 20 additions & 10 deletions vclusterops/https_get_up_nodes_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ func (op *httpsGetUpNodesOp) execute(execContext *opEngineExecContext) error {
func (op *httpsGetUpNodesOp) processResult(execContext *opEngineExecContext) error {
var allErrs error
upHosts := mapset.NewSet[string]()
computeHosts := mapset.NewSet[string]()
upScInfo := make(map[string]string)
exceptionHosts := []string{}
downHosts := []string{}
Expand All @@ -148,8 +149,9 @@ func (op *httpsGetUpNodesOp) processResult(execContext *opEngineExecContext) err
op.logResponse(host, result)
if !result.isPassing() {
allErrs = errors.Join(allErrs, result.err)
if result.isUnauthorizedRequest() || result.isInternalError() {
// Authentication error and any unexpected internal server error
if result.isUnauthorizedRequest() || result.isInternalError() || result.hasPreconditionFailed() {
// Authentication error and any unexpected internal server error, plus compute nodes or nodes
// that haven't joined the cluster yet
exceptionHosts = append(exceptionHosts, host)
continue
}
Expand All @@ -167,16 +169,15 @@ func (op *httpsGetUpNodesOp) processResult(execContext *opEngineExecContext) err
continue
}

if op.cmdType == StopDBCmd || op.cmdType == StopSubclusterCmd {
err = op.validateHosts(nodesStates)
if err != nil {
allErrs = errors.Join(allErrs, err)
break
}
// For certain commands, check hosts in input against those reported from endpoint
err = op.validateHosts(nodesStates)
if err != nil {
allErrs = errors.Join(allErrs, err)
break
}

// Collect all the up hosts
err = op.collectUpHosts(nodesStates, host, upHosts, upScInfo, sandboxInfo, upScNodes, scNodes)
err = op.collectUpHosts(nodesStates, host, upHosts, computeHosts, upScInfo, sandboxInfo, upScNodes, scNodes)
if err != nil {
allErrs = errors.Join(allErrs, err)
return allErrs
Expand All @@ -190,6 +191,7 @@ func (op *httpsGetUpNodesOp) processResult(execContext *opEngineExecContext) err
break
}
}
execContext.computeHosts = computeHosts.ToSlice()
execContext.nodesInfo = upScNodes.ToSlice()
execContext.scNodesInfo = scNodes.ToSlice()
execContext.upHostsToSandboxes = sandboxInfo
Expand Down Expand Up @@ -275,6 +277,10 @@ func (op *httpsGetUpNodesOp) processHostLists(upHosts mapset.Set[string], upScIn

// validateHosts can validate if hosts in user input matches the ones in GET /nodes response
func (op *httpsGetUpNodesOp) validateHosts(nodesStates nodesStateInfo) error {
// only needed for the following commands
if !(op.cmdType == StopDBCmd || op.cmdType == StopSubclusterCmd) {
return nil
}
var dbHosts []string
dbUnexpected := false
unexpectedDBName := ""
Expand Down Expand Up @@ -310,7 +316,7 @@ func (op *httpsGetUpNodesOp) checkUpHostEligible(node *nodeStateInfo) bool {
return true
}

func (op *httpsGetUpNodesOp) collectUpHosts(nodesStates nodesStateInfo, host string, upHosts mapset.Set[string],
func (op *httpsGetUpNodesOp) collectUpHosts(nodesStates nodesStateInfo, host string, upHosts, computeHosts mapset.Set[string],
upScInfo, sandboxInfo map[string]string, upScNodes, scNodes mapset.Set[NodeInfo]) (err error) {
foundSC := false
for _, node := range nodesStates.NodeList {
Expand All @@ -333,6 +339,10 @@ func (op *httpsGetUpNodesOp) collectUpHosts(nodesStates nodesStateInfo, host str
}
}

if node.State == util.NodeComputeState {
computeHosts.Add(node.Address)
}

if op.scName == node.Subcluster {
op.sandbox = node.Sandbox
if node.IsPrimary {
Expand Down
Loading

0 comments on commit 41a8011

Please sign in to comment.