2023-04-10 15:36:59 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2021-03-12 20:57:49 +00:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/posener/complete"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// DefaultHclVolumeInitName is the default name we use when initializing
|
|
|
|
// the example volume file in HCL format
|
|
|
|
DefaultHclVolumeInitName = "volume.hcl"
|
|
|
|
|
|
|
|
// DefaultHclVolumeInitName is the default name we use when initializing
|
|
|
|
// the example volume file in JSON format
|
|
|
|
DefaultJsonVolumeInitName = "volume.json"
|
|
|
|
)
|
|
|
|
|
|
|
|
// VolumeInitCommand generates a new volume spec that you can customize to
|
|
|
|
// your liking, like vagrant init
|
|
|
|
type VolumeInitCommand struct {
|
|
|
|
Meta
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VolumeInitCommand) Help() string {
|
|
|
|
helpText := `
|
2021-04-18 18:14:05 +00:00
|
|
|
Usage: nomad volume init <filename>
|
2021-03-12 20:57:49 +00:00
|
|
|
|
|
|
|
Creates an example volume specification file that can be used as a starting
|
2021-04-18 18:14:05 +00:00
|
|
|
point to customize further. If no filename is give, the default "volume.json"
|
|
|
|
or "volume.hcl" will be used.
|
2021-03-12 20:57:49 +00:00
|
|
|
|
|
|
|
Init Options:
|
|
|
|
|
|
|
|
-json
|
|
|
|
Create an example JSON volume specification.
|
|
|
|
`
|
|
|
|
return strings.TrimSpace(helpText)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VolumeInitCommand) Synopsis() string {
|
|
|
|
return "Create an example volume specification file"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VolumeInitCommand) AutocompleteFlags() complete.Flags {
|
|
|
|
return complete.Flags{
|
|
|
|
"-json": complete.PredictNothing,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VolumeInitCommand) AutocompleteArgs() complete.Predictor {
|
|
|
|
return complete.PredictNothing
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *VolumeInitCommand) Name() string { return "volume init" }
|
|
|
|
|
|
|
|
func (c *VolumeInitCommand) Run(args []string) int {
|
|
|
|
var jsonOutput bool
|
|
|
|
flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
|
|
|
|
flags.Usage = func() { c.Ui.Output(c.Help()) }
|
|
|
|
flags.BoolVar(&jsonOutput, "json", false, "")
|
|
|
|
|
|
|
|
if err := flags.Parse(args); err != nil {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that we get no arguments
|
|
|
|
args = flags.Args()
|
2021-04-18 18:14:05 +00:00
|
|
|
if l := len(args); l > 1 {
|
|
|
|
c.Ui.Error("This command takes no arguments or one: <filename>")
|
2021-03-12 20:57:49 +00:00
|
|
|
c.Ui.Error(commandErrorText(c))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
fileName := DefaultHclVolumeInitName
|
|
|
|
fileContent := defaultHclVolumeSpec
|
|
|
|
if jsonOutput {
|
|
|
|
fileName = DefaultJsonVolumeInitName
|
|
|
|
fileContent = defaultJsonVolumeSpec
|
|
|
|
}
|
2021-04-18 18:14:05 +00:00
|
|
|
if len(args) == 1 {
|
|
|
|
fileName = args[0]
|
|
|
|
}
|
2021-03-12 20:57:49 +00:00
|
|
|
|
|
|
|
// Check if the file already exists
|
|
|
|
_, err := os.Stat(fileName)
|
|
|
|
if err != nil && !os.IsNotExist(err) {
|
|
|
|
c.Ui.Error(fmt.Sprintf("Failed to stat %q: %v", fileName, err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
c.Ui.Error(fmt.Sprintf("Volume specification %q already exists", fileName))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write out the example
|
2023-03-08 15:20:04 +00:00
|
|
|
err = os.WriteFile(fileName, []byte(fileContent), 0660)
|
2021-03-12 20:57:49 +00:00
|
|
|
if err != nil {
|
|
|
|
c.Ui.Error(fmt.Sprintf("Failed to write %q: %v", fileName, err))
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Success
|
|
|
|
c.Ui.Output(fmt.Sprintf("Example volume specification written to %s", fileName))
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
var defaultHclVolumeSpec = strings.TrimSpace(`
|
2021-03-31 17:29:14 +00:00
|
|
|
id = "ebs_prod_db1"
|
2022-03-29 18:46:39 +00:00
|
|
|
namespace = "default"
|
2021-03-31 17:29:14 +00:00
|
|
|
name = "database"
|
|
|
|
type = "csi"
|
|
|
|
plugin_id = "plugin_id"
|
|
|
|
|
|
|
|
# For 'nomad volume register', provide the external ID from the storage
|
|
|
|
# provider. This field should be omitted when creating a volume with
|
|
|
|
# 'nomad volume create'
|
|
|
|
external_id = "vol-23452345"
|
|
|
|
|
|
|
|
# For 'nomad volume create', specify a snapshot ID or volume to clone. You can
|
|
|
|
# specify only one of these two fields.
|
|
|
|
snapshot_id = "snap-12345"
|
|
|
|
# clone_id = "vol-abcdef"
|
|
|
|
|
|
|
|
# Optional: for 'nomad volume create', specify a maximum and minimum capacity.
|
|
|
|
# Registering an existing volume will record but ignore these fields.
|
|
|
|
capacity_min = "10GiB"
|
|
|
|
capacity_max = "20G"
|
|
|
|
|
2021-04-06 18:29:28 +00:00
|
|
|
# Required (at least one): for 'nomad volume create', specify one or more
|
|
|
|
# capabilities to validate. Registering an existing volume will record but
|
|
|
|
# ignore these fields.
|
2021-03-31 17:29:14 +00:00
|
|
|
capability {
|
2022-03-01 15:15:46 +00:00
|
|
|
access_mode = "single-node-writer"
|
2021-03-31 17:29:14 +00:00
|
|
|
attachment_mode = "file-system"
|
|
|
|
}
|
|
|
|
|
|
|
|
capability {
|
|
|
|
access_mode = "single-node-reader"
|
|
|
|
attachment_mode = "block-device"
|
|
|
|
}
|
2021-03-12 20:57:49 +00:00
|
|
|
|
2021-04-06 18:29:28 +00:00
|
|
|
# Optional: for 'nomad volume create', specify mount options to validate for
|
|
|
|
# 'attachment_mode = "file-system". Registering an existing volume will record
|
|
|
|
# but ignore these fields.
|
2021-03-12 20:57:49 +00:00
|
|
|
mount_options {
|
|
|
|
fs_type = "ext4"
|
|
|
|
mount_flags = ["ro"]
|
|
|
|
}
|
2021-03-31 17:29:14 +00:00
|
|
|
|
2022-03-01 15:15:46 +00:00
|
|
|
# Optional: specify one or more locations where the volume must be accessible
|
|
|
|
# from. Refer to the plugin documentation for what segment values are supported.
|
|
|
|
topology_request {
|
|
|
|
preferred {
|
|
|
|
topology { segments { rack = "R1" } }
|
|
|
|
}
|
|
|
|
required {
|
|
|
|
topology { segments { rack = "R1" } }
|
|
|
|
topology { segments { rack = "R2", zone = "us-east-1a" } }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-31 17:29:14 +00:00
|
|
|
# Optional: provide any secrets specified by the plugin.
|
2021-03-12 20:57:49 +00:00
|
|
|
secrets {
|
|
|
|
example_secret = "xyzzy"
|
|
|
|
}
|
2021-03-31 17:29:14 +00:00
|
|
|
|
|
|
|
# Optional: provide a map of keys to string values expected by the plugin.
|
2021-03-12 20:57:49 +00:00
|
|
|
parameters {
|
|
|
|
skuname = "Premium_LRS"
|
|
|
|
}
|
2021-03-31 17:29:14 +00:00
|
|
|
|
|
|
|
# Optional: for 'nomad volume register', provide a map of keys to string
|
|
|
|
# values expected by the plugin. This field will populated automatically by
|
|
|
|
# 'nomad volume create'.
|
2021-03-12 20:57:49 +00:00
|
|
|
context {
|
|
|
|
endpoint = "http://192.168.1.101:9425"
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
|
|
|
|
var defaultJsonVolumeSpec = strings.TrimSpace(`
|
|
|
|
{
|
|
|
|
"id": "ebs_prod_db1",
|
2022-03-29 18:46:39 +00:00
|
|
|
"namespace": "default",
|
2021-03-12 20:57:49 +00:00
|
|
|
"name": "database",
|
|
|
|
"type": "csi",
|
2021-03-31 17:29:14 +00:00
|
|
|
"plugin_id": "plugin_id",
|
2021-03-12 20:57:49 +00:00
|
|
|
"external_id": "vol-23452345",
|
2021-03-31 17:29:14 +00:00
|
|
|
"snapshot_id": "snap-12345",
|
|
|
|
"capacity_min": "10GiB",
|
|
|
|
"capacity_max": "20G",
|
|
|
|
"capability": [
|
|
|
|
{
|
|
|
|
"access_mode": "single-node-writer",
|
|
|
|
"attachment_mode": "file-system"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"access_mode": "single-node-reader",
|
|
|
|
"attachment_mode": "block-device"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"context": [
|
|
|
|
{
|
|
|
|
"endpoint": "http://192.168.1.101:9425"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"mount_options": [
|
|
|
|
{
|
|
|
|
"fs_type": "ext4",
|
|
|
|
"mount_flags": [
|
|
|
|
"ro"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
2022-03-01 15:15:46 +00:00
|
|
|
"topology_request": {
|
|
|
|
"preferred": [
|
|
|
|
{
|
|
|
|
"topology": {
|
|
|
|
"segments": {
|
|
|
|
"rack": "R1"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"required": [
|
|
|
|
{
|
|
|
|
"topology": {
|
|
|
|
"segments": {
|
|
|
|
"rack": "R1"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"topology": {
|
|
|
|
"segments": {
|
|
|
|
"rack": "R2",
|
|
|
|
"zone": "us-east-1a"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
2021-03-31 17:29:14 +00:00
|
|
|
"parameters": [
|
|
|
|
{
|
|
|
|
"skuname": "Premium_LRS"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"secrets": [
|
|
|
|
{
|
|
|
|
"example_secret": "xyzzy"
|
|
|
|
}
|
|
|
|
]
|
2021-03-12 20:57:49 +00:00
|
|
|
}
|
|
|
|
`)
|