Skip to content

Commit

Permalink
Sync from server repo (5ce311191a4)
Browse files Browse the repository at this point in the history
  • Loading branch information
releng committed Nov 25, 2024
1 parent cf50448 commit cff7b45
Show file tree
Hide file tree
Showing 19 changed files with 757 additions and 63 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
}
16 changes: 16 additions & 0 deletions commands/user_input_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"testing"

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

Expand Down Expand Up @@ -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")
Expand Down
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
37 changes: 34 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 Expand Up @@ -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{}
}
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
Loading

0 comments on commit cff7b45

Please sign in to comment.