Skip to content

Commit

Permalink
Sync from server repo (808f7b27c25)
Browse files Browse the repository at this point in the history
  • Loading branch information
releng committed Sep 11, 2024
1 parent 9abf223 commit fc237d5
Show file tree
Hide file tree
Showing 24 changed files with 682 additions and 273 deletions.
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

[![Go Reference](https://pkg.go.dev/badge/github.com/vertica/vcluster.svg)](https://pkg.go.dev/github.com/vertica/vcluster)

This repository contains the vcluster-ops Go library and command-line interface to administer a Vertica cluster with a REST API. The REST API endpoints are exposed by the following services:
This repository contains the vcluster-ops Go library and command-line
interface to administer a Vertica cluster with a REST API. The REST API
endpoints are exposed by the following services:
- Node Management Agent (NMA)
- Embedded HTTPS service

This CLI tool combines REST calls to provide a coherent Go interface so that you can perform the following administrator operations:
This CLI tool combines REST calls to provide a coherent Go interface so that
you can perform the following administrator operations:
- Create a database
- Scale a cluster up and down
- Restart a cluster
Expand Down Expand Up @@ -58,9 +61,14 @@ directories in this project.


## Usage
Each source file in `vclusterops/` contains a `V<Operation>Options` struct with option fields that you can set for that operation, and a `V<Operation>OptionsFactory` factory function that returns a struct with sensible option defaults. General database and authentication options are available in `DatabaseOptions` in `vclusterops/vcluster_database_options.go`.
Each source file in `vclusterops/` contains a `V<Operation>Options` struct
with option fields that you can set for that operation, and a `V<Operation>OptionsFactory`
factory function that returns a struct with sensible option defaults. General
database and authentication options are available in `DatabaseOptions` in
`vclusterops/vcluster_database_options.go`.

The following example imports the `vclusterops` library, and then calls functions from `vclusterops/create_db.go` to create a database:
The following example imports the `vclusterops` library, and then calls
functions from `vclusterops/create_db.go` to create a database:


```
Expand Down Expand Up @@ -94,4 +102,5 @@ We can use similar way to set up and call other vcluster-ops commands.


## Licensing
vcluster is open source code and is under the Apache 2.0 license. Please see `LICENSE` for details.
vcluster is open source and is under the Apache 2.0 license. Please see
`LICENSE` for details.
7 changes: 6 additions & 1 deletion commands/cluster_command_launcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ const (
dataPathKey = "dataPath"
communalStorageLocationFlag = "communal-storage-location"
communalStorageLocationKey = "communalStorageLocation"
archiveNameFlag = "archive-name"
archiveNameKey = "archiveName"
ipv6Flag = "ipv6"
ipv6Key = "ipv6"
eonModeFlag = "eon-mode"
Expand Down Expand Up @@ -156,6 +158,7 @@ var flagKeyMap = map[string]string{
verboseFlag: verboseKey,
outputFileFlag: outputFileKey,
sandboxFlag: sandboxKey,
archiveNameFlag: archiveNameKey,
targetDBNameFlag: targetDBNameKey,
targetHostsFlag: targetHostsKey,
targetUserNameFlag: targetUserNameKey,
Expand Down Expand Up @@ -213,8 +216,9 @@ const (
showRestorePointsSubCmd = "show_restore_points"
installPkgSubCmd = "install_packages"
// hidden Cmds (for internal testing only)
getDrainingStatusSubCmd = "get_draining_status"
promoteSandboxSubCmd = "promote_sandbox"
saveRestorePointsSubCmd = "save_restore_point"
getDrainingStatusSubCmd = "get_draining_status"
)

// cmdGlobals holds global variables shared by multiple
Expand Down Expand Up @@ -580,6 +584,7 @@ func constructCmds() []*cobra.Command {
// hidden cmds (for internal testing only)
makeCmdGetDrainingStatus(),
makeCmdPromoteSandbox(),
makeCmdSaveRestorePoint(),
}
}

Expand Down
1 change: 0 additions & 1 deletion commands/cmd_create_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,6 @@ func (c *CmdCreateDB) Run(vcc vclusterops.ClusterCommands) error {
vcc.V(1).Info("Called method Run()")
vdb, createError := vcc.VCreateDatabase(c.createDBOptions)
if createError != nil {
vcc.LogError(createError, "Failed to create the database.")
return createError
}

Expand Down
161 changes: 161 additions & 0 deletions commands/cmd_save_restore_point.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
(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/spf13/viper"
"github.com/vertica/vcluster/vclusterops"
"github.com/vertica/vcluster/vclusterops/vlog"
)

/* CmdSaveRestorePoint
*
* Parses arguments to save-restore-points and calls
* the high-level function for save-restore-points.
*
* Implements ClusterCommand interface
*/

type CmdSaveRestorePoint struct {
CmdBase
saveRestoreOptions *vclusterops.VSaveRestorePointOptions
}

func makeCmdSaveRestorePoint() *cobra.Command {
newCmd := &CmdSaveRestorePoint{}
opt := vclusterops.VSaveRestorePointFactory()
newCmd.saveRestoreOptions = &opt

cmd := makeBasicCobraCmd(
newCmd,
saveRestorePointsSubCmd,
"Save a restore point in a given archive.",
`Save a restore point in a given archive.
Examples:
# Save restore point in a given archive with user input
vcluster save_restore_point --db-name test_db \
--archive-name ARCHIVE_ONE
# Save restore point for a sandbox
vcluster save_restore_point --db-name test_db \
--archive-name ARCHIVE_ONE --sandbox SANDBOX_ONE
`,
[]string{dbNameFlag, hostsFlag, passwordFlag,
ipv6Flag, configFlag, eonModeFlag},
)

// local flags
newCmd.setLocalFlags(cmd)

// require db-name and archive-name
markFlagsRequired(cmd, dbNameFlag, archiveNameFlag)

// hide this subcommand
cmd.Hidden = true

return cmd
}

// setLocalFlags will set the local flags the command has
func (c *CmdSaveRestorePoint) setLocalFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(
&c.saveRestoreOptions.ArchiveName,
archiveNameFlag,
"",
"Collection of restore points that belong to a certain archive.",
)
cmd.Flags().StringVar(
&c.saveRestoreOptions.Sandbox,
sandboxFlag,
"",
"The name of target sandbox",
)
}

func (c *CmdSaveRestorePoint) 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.saveRestoreOptions.DatabaseOptions)

// save_restore_point only works for an Eon db so we assume the user always runs this subcommand
// on an Eon db. When Eon mode cannot be found in config file, we set its value to true.
if !viper.IsSet(eonModeKey) {
c.saveRestoreOptions.IsEon = true
}

return c.validateParse(logger)
}

// all validations of the arguments should go in here
func (c *CmdSaveRestorePoint) validateParse(logger vlog.Printer) error {
logger.Info("Called validateParse()")

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

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

err = c.setConfigParam(&c.saveRestoreOptions.DatabaseOptions)
if err != nil {
return err
}

err = c.setDBPassword(&c.saveRestoreOptions.DatabaseOptions)
if err != nil {
return err
}

return nil
}

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

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

options := c.saveRestoreOptions

err := vcc.VSaveRestorePoint(options)
if err != nil {
vcc.LogError(err, "failed to save restore points", "DBName", options.DBName)
return err
}

vcc.DisplayInfo("Successfully saved restore points in database %s", options.DBName)
return nil
}

// SetDatabaseOptions will assign a vclusterops.DatabaseOptions instance to the one in CmdSaveRestorePoint
func (c *CmdSaveRestorePoint) SetDatabaseOptions(opt *vclusterops.DatabaseOptions) {
c.saveRestoreOptions.DatabaseOptions = *opt
}
3 changes: 2 additions & 1 deletion vclusterops/add_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,8 @@ func (vcc VClusterCommands) produceAddNodeInstructions(vdb *VCoordinationDatabas
produceTransferConfigOps(&instructions,
nil,
vdb.HostList,
vdb /*db configurations retrieved from a running db*/)
vdb, /*db configurations retrieved from a running db*/
nil /*Sandbox name*/)

nmaStartNewNodesOp := makeNMAStartNodeOpWithVDB(newHosts, options.StartUpConf, vdb)
httpsPollNodeStateOp, err := makeHTTPSPollNodeStateOp(newHosts, usePassword, username, password, options.TimeOut)
Expand Down
23 changes: 15 additions & 8 deletions vclusterops/cluster_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ const (
)

const (
SuccessCode = 200
MultipleChoiceCode = 300
UnauthorizedCode = 401
InternalErrorCode = 500
SuccessCode = 200
MultipleChoiceCode = 300
UnauthorizedCode = 401
PreconditionFailedCode = 412
InternalErrorCode = 500
)

// hostHTTPResult is used to save result of an Adapter's sendRequest(...) function
Expand All @@ -97,13 +98,17 @@ const respSuccStatusCode = 0
// The HTTP response with a 401 status code can have several scenarios:
// 1. Wrong password
// 2. Wrong certificate
// 3. The local node has not yet joined the cluster; the HTTP server will accept connections once the node joins the cluster.
// HTTPCheckDBRunningOp in create_db need to check all scenarios to see any HTTP running
// For HTTPSPollNodeStateOp in start_db, it requires only handling the first and second scenarios
// HTTPCheckDBRunningOp in create_db and HTTPSPollNodeStateOp in start_db need to handle these scenarios
func (hostResult *hostHTTPResult) isUnauthorizedRequest() bool {
return hostResult.statusCode == UnauthorizedCode
}

// The HTTP response with a 412 may happen if
// the local node has not yet joined the cluster; the HTTP server will accept connections once the node joins the cluster.
func (hostResult *hostHTTPResult) hasPreconditionFailed() bool {
return hostResult.statusCode == PreconditionFailedCode
}

// isSuccess returns true if status code is 200
func (hostResult *hostHTTPResult) isSuccess() bool {
return hostResult.statusCode == SuccessCode
Expand All @@ -129,7 +134,8 @@ func (hostResult *hostHTTPResult) isInternalError() bool {
}

func (hostResult *hostHTTPResult) isHTTPRunning() bool {
if hostResult.isPassing() || hostResult.isUnauthorizedRequest() || hostResult.isInternalError() {
if hostResult.isPassing() || hostResult.isUnauthorizedRequest() ||
hostResult.isInternalError() || hostResult.hasPreconditionFailed() {
return true
}
return false
Expand Down Expand Up @@ -561,6 +567,7 @@ type ClusterCommands interface {
VSandbox(options *VSandboxOptions) error
VScrutinize(options *VScrutinizeOptions) error
VShowRestorePoints(options *VShowRestorePointsOptions) (restorePoints []RestorePoint, err error)
VSaveRestorePoint(options *VSaveRestorePointOptions) (err error)
VStartDatabase(options *VStartDatabaseOptions) (vdbPtr *VCoordinationDatabase, err error)
VStartNodes(options *VStartNodesOptions) error
VStartSubcluster(startScOpt *VStartScOptions) error
Expand Down
2 changes: 2 additions & 0 deletions vclusterops/cmd_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
SandboxSCCmd
UnsandboxSCCmd
ShowRestorePointsCmd
SaveRestorePointsCmd
InstallPackagesCmd
ConfigRecoverCmd
GetDrainingStatusCmd
Expand Down Expand Up @@ -60,6 +61,7 @@ var cmdStringMap = map[CmdType]string{
SandboxSCCmd: "sandbox_subcluster",
UnsandboxSCCmd: "unsandbox_subcluster",
ShowRestorePointsCmd: "show_restore_points",
SaveRestorePointsCmd: "save_restore_point",
InstallPackagesCmd: "install_packages",
ConfigRecoverCmd: "manage_config_recover",
GetDrainingStatusCmd: "get_draining_status",
Expand Down
4 changes: 3 additions & 1 deletion vclusterops/create_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ func (vcc VClusterCommands) VCreateDatabase(options *VCreateDatabaseOptions) (VC
vdb := makeVCoordinationDatabase()
err := vdb.setFromCreateDBOptions(options, vcc.Log)
if err != nil {
vcc.Log.Error(err, "fail to create database")
return vdb, err
}
// produce instructions
Expand Down Expand Up @@ -489,7 +490,8 @@ func (vcc VClusterCommands) produceCreateDBWorkerNodesInstructions(
&instructions,
bootstrapHost,
vdb.HostList,
vdb /*db configurations retrieved from a running db*/)
vdb, /*db configurations retrieved from a running db*/
nil /*sandbox name*/)
nmaStartNewNodesOp := makeNMAStartNodeOpWithVDB(newNodeHosts, options.StartUpConf, vdb)
instructions = append(instructions, &nmaStartNewNodesOp)
}
Expand Down
Loading

0 comments on commit fc237d5

Please sign in to comment.