github.com/ThomasObenaus/nomad@v0.11.1/command/volume_register.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "strings" 8 9 "github.com/hashicorp/hcl" 10 "github.com/hashicorp/hcl/hcl/ast" 11 "github.com/posener/complete" 12 ) 13 14 type VolumeRegisterCommand struct { 15 Meta 16 } 17 18 func (c *VolumeRegisterCommand) Help() string { 19 helpText := ` 20 Usage: nomad volume register [options] <input> 21 22 Creates or updates a volume in Nomad. The volume must exist on the remote 23 storage provider before it can be used by a task. 24 25 If the supplied path is "-" the volume file is read from stdin. Otherwise, it 26 is read from the file at the supplied path. 27 28 General Options: 29 30 ` + generalOptionsUsage() 31 32 return strings.TrimSpace(helpText) 33 } 34 35 func (c *VolumeRegisterCommand) AutocompleteFlags() complete.Flags { 36 return c.Meta.AutocompleteFlags(FlagSetClient) 37 } 38 39 func (c *VolumeRegisterCommand) AutocompleteArgs() complete.Predictor { 40 return complete.PredictFiles("*") 41 } 42 43 func (c *VolumeRegisterCommand) Synopsis() string { 44 return "Create or update a volume" 45 } 46 47 func (c *VolumeRegisterCommand) Name() string { return "volume register" } 48 49 func (c *VolumeRegisterCommand) Run(args []string) int { 50 flags := c.Meta.FlagSet(c.Name(), FlagSetClient) 51 flags.Usage = func() { c.Ui.Output(c.Help()) } 52 53 if err := flags.Parse(args); err != nil { 54 c.Ui.Error(fmt.Sprintf("Error parsing arguments %s", err)) 55 return 1 56 } 57 58 // Check that we get exactly one argument 59 args = flags.Args() 60 if l := len(args); l != 1 { 61 c.Ui.Error("This command takes one argument: <input>") 62 c.Ui.Error(commandErrorText(c)) 63 return 1 64 } 65 66 // Read the file contents 67 file := args[0] 68 var rawVolume []byte 69 var err error 70 if file == "-" { 71 rawVolume, err = ioutil.ReadAll(os.Stdin) 72 if err != nil { 73 c.Ui.Error(fmt.Sprintf("Failed to read stdin: %v", err)) 74 return 1 75 } 76 } else { 77 rawVolume, err = ioutil.ReadFile(file) 78 if err != nil { 79 c.Ui.Error(fmt.Sprintf("Failed to read file: %v", err)) 80 return 1 81 } 82 } 83 84 ast, volType, err := parseVolumeType(string(rawVolume)) 85 if err != nil { 86 c.Ui.Error(fmt.Sprintf("Error parsing the volume type: %s", err)) 87 return 1 88 } 89 volType = strings.ToLower(volType) 90 91 // Get the HTTP client 92 client, err := c.Meta.Client() 93 if err != nil { 94 c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err)) 95 return 1 96 } 97 98 switch volType { 99 case "csi": 100 code := c.csiRegister(client, ast) 101 if code != 0 { 102 return code 103 } 104 default: 105 c.Ui.Error(fmt.Sprintf("Error unknown volume type: %s", volType)) 106 return 1 107 } 108 109 return 0 110 } 111 112 // parseVolume is used to parse the quota specification from HCL 113 func parseVolumeType(input string) (*ast.File, string, error) { 114 // Parse the AST first 115 ast, err := hcl.Parse(input) 116 if err != nil { 117 return nil, "", fmt.Errorf("parse error: %v", err) 118 } 119 120 // Decode the type, so we can dispatch on it 121 dispatch := &struct { 122 T string `hcl:"type"` 123 }{} 124 err = hcl.DecodeObject(dispatch, ast) 125 if err != nil { 126 return nil, "", fmt.Errorf("dispatch error: %v", err) 127 } 128 129 return ast, dispatch.T, nil 130 }