Skip to content

Commit

Permalink
Sync from server repo (942e1d19ece)
Browse files Browse the repository at this point in the history
  • Loading branch information
releng committed Dec 2, 2024
1 parent cf50448 commit c6b705e
Showing 21 changed files with 780 additions and 66 deletions.
4 changes: 4 additions & 0 deletions commands/cluster_command_launcher.go
Original file line number Diff line number Diff line change
@@ -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"
@@ -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
@@ -630,6 +633,7 @@ func constructCmds() []*cobra.Command {
makeCmdPromoteSandbox(),
makeCmdCreateArchive(),
makeCmdSaveRestorePoint(),
makeCmdUpgradeLicense(),
}
}

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
}
16 changes: 16 additions & 0 deletions commands/user_input_test.go
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/vertica/vcluster/vclusterops"
"gopkg.in/yaml.v3"
)

@@ -90,6 +91,21 @@ func TestManageReplication(t *testing.T) {
assert.ErrorContains(t, err, `unknown command "test" for "vcluster replication start"`)
}

func TestAsyncReplicationErrorMessage(t *testing.T) {
vcommand := vclusterops.VClusterCommands{}
replicationDatabaseOptions := vclusterops.VReplicationDatabaseFactory()
replicationDatabaseOptions.DBName = "db"
replicationDatabaseOptions.Hosts = []string{"12.34.56.78"}
replicationDatabaseOptions.IsEon = true
password := "password"
replicationDatabaseOptions.Password = &password
replicationDatabaseOptions.TargetDB.Hosts = []string{"23.45.67.89"}
replicationDatabaseOptions.TargetDB.DBName = "targetDb"
replicationDatabaseOptions.TableOrSchemaName = ".ns1.s1.*"
_, err := vcommand.VReplicateDatabase(&replicationDatabaseOptions)
assert.ErrorContains(t, err, "not allowed in --table-or-schema-name. HINT:")
}

func TestCreateConnectionFileWrongFileType(t *testing.T) {
// vertica_connection.txt will not be created and a unique name is not required
var tempConnFilePath = filepath.Join(os.TempDir(), "vertica_connection.txt")
1 change: 1 addition & 0 deletions vclusterops/cluster_op.go
Original file line number Diff line number Diff line change
@@ -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 {
1 change: 1 addition & 0 deletions vclusterops/cluster_op_engine_context.go
Original file line number Diff line number Diff line change
@@ -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

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

var cmdStringMap = map[CmdType]string{
@@ -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 {
37 changes: 34 additions & 3 deletions vclusterops/coordinator_database.go
Original file line number Diff line number Diff line change
@@ -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)
@@ -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
@@ -380,6 +388,29 @@ type VCoordinationNode struct {
ControlNode string
}

func CloneVCoordinationNode(node *VCoordinationNode) *VCoordinationNode {
if node == nil {
return nil
}
return &VCoordinationNode{
Name: node.Name,
Address: node.Address,
CatalogPath: node.CatalogPath,
StorageLocations: append([]string{}, node.StorageLocations...), // Create a new slice
UserStorageLocations: append([]string{}, node.UserStorageLocations...), // Create a new slice
DepotPath: node.DepotPath,
Port: node.Port,
ControlAddressFamily: node.ControlAddressFamily,
IsPrimary: node.IsPrimary,
State: node.State,
Subcluster: node.Subcluster,
Sandbox: node.Sandbox,
Version: node.Version,
IsControlNode: node.IsControlNode,
ControlNode: node.ControlNode,
}
}

func makeVCoordinationNode() VCoordinationNode {
return VCoordinationNode{}
}
3 changes: 3 additions & 0 deletions vclusterops/fetch_database.go
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 1 addition & 1 deletion vclusterops/fetch_node_state.go
Original file line number Diff line number Diff line change
@@ -194,7 +194,7 @@ func buildNodeStateList(vdb *VCoordinationDatabase, forDownDatabase bool) []Node
nodeInfo.IsPrimary = n.IsPrimary
nodeInfo.Name = n.Name
nodeInfo.Sandbox = n.Sandbox
if forDownDatabase {
if forDownDatabase && n.State == "" {
nodeInfo.State = util.NodeDownState
} else {
nodeInfo.State = n.State
6 changes: 6 additions & 0 deletions vclusterops/https_check_subcluster_sandbox_op.go
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ package vclusterops
import (
"errors"
"fmt"

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

type httpsCheckSubclusterSandboxOp struct {
@@ -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)
2 changes: 1 addition & 1 deletion vclusterops/https_create_archive_op.go
Original file line number Diff line number Diff line change
@@ -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)

Loading

0 comments on commit c6b705e

Please sign in to comment.