-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Matt Spilchen
committed
Jan 18, 2024
1 parent
288b84d
commit 7a8dd47
Showing
8 changed files
with
493 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package commands | ||
|
||
import ( | ||
"flag" | ||
|
||
"github.com/vertica/vcluster/vclusterops" | ||
"github.com/vertica/vcluster/vclusterops/util" | ||
"github.com/vertica/vcluster/vclusterops/vlog" | ||
) | ||
|
||
/* CmdShowRestorePoints | ||
* | ||
* Implements ClusterCommand interface | ||
*/ | ||
type CmdShowRestorePoints struct { | ||
CmdBase | ||
showRestorePointsOptions *vclusterops.VShowRestorePointsOptions | ||
configurationParams *string // raw input from user, need further processing | ||
|
||
} | ||
|
||
func makeCmdShowRestorePoints() *CmdShowRestorePoints { | ||
// CmdShowRestorePoints | ||
newCmd := &CmdShowRestorePoints{} | ||
|
||
// parser, used to parse command-line flags | ||
newCmd.parser = flag.NewFlagSet("show_restore_points", flag.ExitOnError) | ||
showRestorePointsOptions := vclusterops.VShowRestorePointsFactory() | ||
|
||
// require flags | ||
showRestorePointsOptions.DBName = newCmd.parser.String("db-name", "", "The name of the database to show restore points") | ||
showRestorePointsOptions.CommunalStorageLocation = newCmd.parser.String("communal-storage-location", "", | ||
util.GetEonFlagMsg("Location of communal storage")) | ||
|
||
// optional flags | ||
newCmd.configurationParams = newCmd.parser.String("config-param", "", util.GetOptionalFlagMsg( | ||
"Comma-separated list of NAME=VALUE pairs for configuration parameters")) | ||
newCmd.hostListStr = newCmd.parser.String("hosts", "", util.GetOptionalFlagMsg("Comma-separated list of hosts to participate in database."+ | ||
" Use it when you do not trust "+vclusterops.ConfigFileName)) | ||
newCmd.ipv6 = newCmd.parser.Bool("ipv6", false, "Whether the database hosts use IPv6 addresses") | ||
|
||
showRestorePointsOptions.Password = newCmd.parser.String("password", "", util.GetOptionalFlagMsg("Database password in single quotes")) | ||
showRestorePointsOptions.HonorUserInput = newCmd.parser.Bool("honor-user-input", false, | ||
util.GetOptionalFlagMsg("Forcefully use the user's input instead of reading the options from "+vclusterops.ConfigFileName)) | ||
showRestorePointsOptions.ConfigDirectory = newCmd.parser.String("config-directory", "", | ||
util.GetOptionalFlagMsg("Directory where "+vclusterops.ConfigFileName+" is located")) | ||
|
||
newCmd.showRestorePointsOptions = &showRestorePointsOptions | ||
|
||
return newCmd | ||
} | ||
|
||
func (c *CmdShowRestorePoints) CommandType() string { | ||
return "show_restore_points" | ||
} | ||
|
||
func (c *CmdShowRestorePoints) Parse(inputArgv []string, logger vlog.Printer) error { | ||
c.argv = inputArgv | ||
err := c.ValidateParseMaskedArgv(c.CommandType(), logger) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if !util.IsOptionSet(c.parser, "ipv6") { | ||
c.CmdBase.ipv6 = nil | ||
} | ||
|
||
if !util.IsOptionSet(c.parser, "config-directory") { | ||
c.showRestorePointsOptions.ConfigDirectory = nil | ||
} | ||
|
||
return c.validateParse(logger) | ||
} | ||
|
||
func (c *CmdShowRestorePoints) validateParse(logger vlog.Printer) error { | ||
logger.Info("Called validateParse()") | ||
|
||
// check the format of configuration params string, and parse it into configParams | ||
configurationParams, err := util.ParseConfigParams(*c.configurationParams) | ||
if err != nil { | ||
return err | ||
} | ||
if configurationParams != nil { | ||
c.showRestorePointsOptions.ConfigurationParameters = configurationParams | ||
} | ||
|
||
return c.ValidateParseBaseOptions(&c.showRestorePointsOptions.DatabaseOptions) | ||
} | ||
|
||
func (c *CmdShowRestorePoints) Analyze(logger vlog.Printer) error { | ||
logger.Info("Called method Analyze()") | ||
return nil | ||
} | ||
|
||
func (c *CmdShowRestorePoints) Run(vcc vclusterops.VClusterCommands) error { | ||
vcc.Log.V(1).Info("Called method Run()") | ||
|
||
options := c.showRestorePointsOptions | ||
config, err := options.GetDBConfig(vcc) | ||
if err != nil { | ||
return err | ||
} | ||
options.Config = config | ||
|
||
restorePoints, err := vcc.VShowRestorePoints(options) | ||
if err != nil { | ||
vcc.Log.Error(err, "fail to show restore points", "DBName", *options.DBName) | ||
return err | ||
} | ||
|
||
vcc.Log.PrintInfo("Successfully show restore points %v in database %s", restorePoints, *options.DBName) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* | ||
(c) Copyright [2023] 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 vclusterops | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/vertica/vcluster/vclusterops/vlog" | ||
) | ||
|
||
type nmaShowRestorePointsOp struct { | ||
opBase | ||
dbName string | ||
communalLocation string | ||
configurationParameters map[string]string | ||
} | ||
|
||
type showRestorePointsRequestData struct { | ||
DBName string `json:"db_name"` | ||
CommunalLocation string `json:"communal_location"` | ||
Parameters map[string]string `json:"parameters,omitempty"` | ||
} | ||
|
||
// This op is used to show restore points in a database | ||
func makeNMAShowRestorePointsOp(logger vlog.Printer, | ||
hosts []string, dbName, communalLocation string, configurationParameters map[string]string) nmaShowRestorePointsOp { | ||
return nmaShowRestorePointsOp{ | ||
opBase: opBase{ | ||
name: "NMAShowRestorePointsOp", | ||
logger: logger.WithName("NMAShowRestorePointsOp"), | ||
hosts: hosts, | ||
}, | ||
dbName: dbName, | ||
configurationParameters: configurationParameters, | ||
communalLocation: communalLocation, | ||
} | ||
} | ||
|
||
// make https json data | ||
func (op *nmaShowRestorePointsOp) setupRequestBody() (map[string]string, error) { | ||
hostRequestBodyMap := make(map[string]string, len(op.hosts)) | ||
for _, host := range op.hosts { | ||
requestData := showRestorePointsRequestData{} | ||
requestData.DBName = op.dbName | ||
requestData.CommunalLocation = op.communalLocation | ||
requestData.Parameters = op.configurationParameters | ||
|
||
dataBytes, err := json.Marshal(requestData) | ||
if err != nil { | ||
return nil, fmt.Errorf("[%s] fail to marshal request data to JSON string, detail %w", op.name, err) | ||
} | ||
hostRequestBodyMap[host] = string(dataBytes) | ||
} | ||
return hostRequestBodyMap, nil | ||
} | ||
|
||
func (op *nmaShowRestorePointsOp) setupClusterHTTPRequest(hostRequestBodyMap map[string]string) error { | ||
for host, requestBody := range hostRequestBodyMap { | ||
httpRequest := hostHTTPRequest{} | ||
httpRequest.Method = GetMethod | ||
httpRequest.buildNMAEndpoint("restore-points") | ||
httpRequest.RequestData = requestBody | ||
op.clusterHTTPRequest.RequestCollection[host] = httpRequest | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (op *nmaShowRestorePointsOp) prepare(execContext *opEngineExecContext) error { | ||
hostRequestBodyMap, err := op.setupRequestBody() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
execContext.dispatcher.setup(op.hosts) | ||
return op.setupClusterHTTPRequest(hostRequestBodyMap) | ||
} | ||
|
||
func (op *nmaShowRestorePointsOp) execute(execContext *opEngineExecContext) error { | ||
if err := op.runExecute(execContext); err != nil { | ||
return err | ||
} | ||
|
||
return op.processResult(execContext) | ||
} | ||
|
||
func (op *nmaShowRestorePointsOp) finalize(_ *opEngineExecContext) error { | ||
return nil | ||
} | ||
|
||
// RestorePoint contains information about a single restore point. | ||
type RestorePoint struct { | ||
// Name of the archive that this restore point was created in. | ||
Archive string | ||
// The ID of the restore point. This is a form of a UID that is static for the restore point. | ||
ID string | ||
// The current index of this restore point. Lower value means it was taken more recently. | ||
// This changes when new restore points are created. | ||
Index int | ||
// The timestamp when the restore point was created. | ||
Timestamp string | ||
} | ||
|
||
func (op *nmaShowRestorePointsOp) processResult(execContext *opEngineExecContext) error { | ||
var allErrs error | ||
|
||
for host, result := range op.clusterHTTPRequest.ResultCollection { | ||
op.logResponse(host, result) | ||
|
||
if result.isPassing() { | ||
/* [ | ||
{ | ||
"archive": "db", | ||
"id": "4ee4119b-802c-4bb4-94b0-061c8748b602", | ||
"index": 1, | ||
"timestamp": "2023-05-02 14:10:31.038289" | ||
}, | ||
{ | ||
"archive": "db", | ||
"id": "bdaa4764-d8aa-4979-89e5-e642cc58d972", | ||
"index": 2, | ||
"timestamp": "2023-05-02 14:10:28.717667" | ||
} | ||
] | ||
*/ | ||
var responseObj []RestorePoint | ||
err := op.parseAndCheckResponse(host, result.content, &responseObj) | ||
if err != nil { | ||
allErrs = errors.Join(allErrs, err) | ||
continue | ||
} | ||
|
||
op.logger.PrintInfo("[%s] response: %v", op.name, result.content) | ||
execContext.restorePoints = responseObj | ||
return nil | ||
} | ||
|
||
allErrs = errors.Join(allErrs, result.err) | ||
} | ||
return allErrs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
(c) Copyright [2023] 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 vclusterops | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/vertica/vcluster/vclusterops/vlog" | ||
) | ||
|
||
func TestShowRestorePointsRequestBody(t *testing.T) { | ||
const hostName = "host1" | ||
const dbName = "testDB" | ||
const communalLocation = "/communal" | ||
op := makeNMAShowRestorePointsOp(vlog.Printer{}, []string{hostName}, dbName, communalLocation, nil) | ||
|
||
requestBody, err := op.setupRequestBody() | ||
assert.NoError(t, err) | ||
assert.Len(t, requestBody, 1) | ||
assert.Contains(t, requestBody, hostName) | ||
hostReq := requestBody[hostName] | ||
assert.Contains(t, hostReq, `"communal_location":"`+communalLocation+`"`) | ||
assert.Contains(t, hostReq, `"db_name":"`+dbName+`"`) | ||
} |
Oops, something went wrong.