Merge pull request #1150 from hashicorp/f-fs-command
Refactor fs subcommands into fs command
This commit is contained in:
commit
157833b3a1
199
command/fs.go
199
command/fs.go
|
@ -2,11 +2,14 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
"github.com/hashicorp/nomad/api"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
type FSCommand struct {
|
||||
|
@ -14,7 +17,31 @@ type FSCommand struct {
|
|||
}
|
||||
|
||||
func (f *FSCommand) Help() string {
|
||||
return "This command is accessed by using one of the subcommands below."
|
||||
helpText := `
|
||||
Usage: nomad fs <alloc-id> <path>
|
||||
|
||||
fs displays either the contents of an allocation directory for the passed allocation,
|
||||
or displays the file at the given path. The path is relative to the root of the alloc
|
||||
dir and defaults to root if unspecified.
|
||||
|
||||
General Options:
|
||||
|
||||
` + generalOptionsUsage() + `
|
||||
|
||||
-H
|
||||
Machine friendly output.
|
||||
|
||||
-verbose
|
||||
Show full information.
|
||||
|
||||
-job <job-id>
|
||||
Use a random allocation from a specified job-id.
|
||||
|
||||
-stat
|
||||
Show file stat information instead of displaying the file, or listing the directory.
|
||||
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (f *FSCommand) Synopsis() string {
|
||||
|
@ -22,7 +49,173 @@ func (f *FSCommand) Synopsis() string {
|
|||
}
|
||||
|
||||
func (f *FSCommand) Run(args []string) int {
|
||||
return cli.RunResultHelp
|
||||
var verbose, machine, job, stat bool
|
||||
flags := f.Meta.FlagSet("fs-list", FlagSetClient)
|
||||
flags.Usage = func() { f.Ui.Output(f.Help()) }
|
||||
flags.BoolVar(&verbose, "verbose", false, "")
|
||||
flags.BoolVar(&machine, "H", false, "")
|
||||
flags.BoolVar(&job, "job", false, "")
|
||||
flags.BoolVar(&stat, "stat", false, "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
args = flags.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
f.Ui.Error("allocation id or -job is required")
|
||||
return 1
|
||||
}
|
||||
|
||||
path := "/"
|
||||
if len(args) == 2 {
|
||||
path = args[1]
|
||||
}
|
||||
|
||||
client, err := f.Meta.Client()
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error initializing client: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// If -job is specified, use random allocation, otherwise use provided allocation
|
||||
allocID := args[0]
|
||||
if job {
|
||||
allocID, err = getRandomJobAlloc(client, args[0])
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error fetching allocations: %v", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate the id unless full length is requested
|
||||
length := shortId
|
||||
if verbose {
|
||||
length = fullId
|
||||
}
|
||||
// Query the allocation info
|
||||
if len(allocID) == 1 {
|
||||
f.Ui.Error(fmt.Sprintf("Alloc ID must contain at least two characters."))
|
||||
return 1
|
||||
}
|
||||
if len(allocID)%2 == 1 {
|
||||
// Identifiers must be of even length, so we strip off the last byte
|
||||
// to provide a consistent user experience.
|
||||
allocID = allocID[:len(allocID)-1]
|
||||
}
|
||||
|
||||
allocs, _, err := client.Allocations().PrefixList(allocID)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) == 0 {
|
||||
f.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) > 1 {
|
||||
// Format the allocs
|
||||
out := make([]string, len(allocs)+1)
|
||||
out[0] = "ID|Eval ID|Job ID|Task Group|Desired Status|Client Status"
|
||||
for i, alloc := range allocs {
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s",
|
||||
limit(alloc.ID, length),
|
||||
limit(alloc.EvalID, length),
|
||||
alloc.JobID,
|
||||
alloc.TaskGroup,
|
||||
alloc.DesiredStatus,
|
||||
alloc.ClientStatus,
|
||||
)
|
||||
}
|
||||
f.Ui.Output(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", formatList(out)))
|
||||
return 0
|
||||
}
|
||||
// Prefix lookup matched a single allocation
|
||||
alloc, _, err := client.Allocations().Info(allocs[0].ID, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if alloc.DesiredStatus == "failed" {
|
||||
allocID := limit(alloc.ID, length)
|
||||
msg := fmt.Sprintf(`The allocation %q failed to be placed. To see the cause, run:
|
||||
nomad alloc-status %s`, allocID, allocID)
|
||||
f.Ui.Error(msg)
|
||||
return 0
|
||||
}
|
||||
|
||||
// Get file stat info
|
||||
file, _, err := client.AllocFS().Stat(alloc, path, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
// If we want file stats, print those and exit.
|
||||
if stat {
|
||||
// Display the file information
|
||||
out := make([]string, 2)
|
||||
out[0] = "Mode|Size|Modified Time|Name"
|
||||
if file != nil {
|
||||
fn := file.Name
|
||||
if file.IsDir {
|
||||
fn = fmt.Sprintf("%s/", fn)
|
||||
}
|
||||
var size string
|
||||
if machine {
|
||||
size = fmt.Sprintf("%d", file.Size)
|
||||
} else {
|
||||
size = humanize.Bytes(uint64(file.Size))
|
||||
}
|
||||
out[1] = fmt.Sprintf("%s|%s|%s|%s", file.FileMode, size,
|
||||
formatTime(file.ModTime), fn)
|
||||
}
|
||||
f.Ui.Output(formatList(out))
|
||||
return 0
|
||||
}
|
||||
|
||||
// Determine if the path is a file or a directory.
|
||||
if file.IsDir {
|
||||
// We have a directory, list it.
|
||||
files, _, err := client.AllocFS().List(alloc, path, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error listing alloc dir: %s", err))
|
||||
return 1
|
||||
}
|
||||
// Display the file information in a tabular format
|
||||
out := make([]string, len(files)+1)
|
||||
out[0] = "Mode|Size|Modfied Time|Name"
|
||||
for i, file := range files {
|
||||
fn := file.Name
|
||||
if file.IsDir {
|
||||
fn = fmt.Sprintf("%s/", fn)
|
||||
}
|
||||
var size string
|
||||
if machine {
|
||||
size = fmt.Sprintf("%d", file.Size)
|
||||
} else {
|
||||
size = humanize.Bytes(uint64(file.Size))
|
||||
}
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s",
|
||||
file.FileMode,
|
||||
size,
|
||||
formatTime(file.ModTime),
|
||||
fn,
|
||||
)
|
||||
}
|
||||
f.Ui.Output(formatList(out))
|
||||
} else {
|
||||
// We have a file, cat it.
|
||||
r, _, err := client.AllocFS().Cat(alloc, path, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error reading file: %s", err))
|
||||
return 1
|
||||
}
|
||||
io.Copy(os.Stdout, r)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Get Random Allocation ID from a known jobID. Prefer to use a running allocation,
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FSCatCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (f *FSCatCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: nomad fs cat <alloc-id> <path>
|
||||
|
||||
Dispays a file in an allocation directory at the given path.
|
||||
The path is relative to the allocation directory and defaults to root if unspecified.
|
||||
|
||||
General Options:
|
||||
|
||||
` + generalOptionsUsage() + `
|
||||
|
||||
Cat Options:
|
||||
|
||||
-verbose
|
||||
Show full information.
|
||||
|
||||
-job <job-id>
|
||||
Use a random allocation from a specified job-id.
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (f *FSCatCommand) Synopsis() string {
|
||||
return "Cat a file in an allocation directory"
|
||||
}
|
||||
|
||||
func (f *FSCatCommand) Run(args []string) int {
|
||||
var verbose, job bool
|
||||
flags := f.Meta.FlagSet("fs-list", FlagSetClient)
|
||||
flags.Usage = func() { f.Ui.Output(f.Help()) }
|
||||
flags.BoolVar(&verbose, "verbose", false, "")
|
||||
flags.BoolVar(&job, "job", false, "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
args = flags.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
f.Ui.Error("allocation id is a required parameter")
|
||||
return 1
|
||||
}
|
||||
|
||||
path := "/"
|
||||
if len(args) == 2 {
|
||||
path = args[1]
|
||||
}
|
||||
|
||||
client, err := f.Meta.Client()
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error initializing client: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// If -job is specified, use random allocation, otherwise use provided allocation
|
||||
allocID := args[0]
|
||||
if job {
|
||||
allocID, err = getRandomJobAlloc(client, args[0])
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying API: %v", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate the id unless full length is requested
|
||||
length := shortId
|
||||
if verbose {
|
||||
length = fullId
|
||||
}
|
||||
// Query the allocation info
|
||||
if len(allocID) == 1 {
|
||||
f.Ui.Error(fmt.Sprintf("Alloc ID must contain at least two characters."))
|
||||
return 1
|
||||
}
|
||||
if len(allocID)%2 == 1 {
|
||||
// Identifiers must be of even length, so we strip off the last byte
|
||||
// to provide a consistent user experience.
|
||||
allocID = allocID[:len(allocID)-1]
|
||||
}
|
||||
|
||||
allocs, _, err := client.Allocations().PrefixList(allocID)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) == 0 {
|
||||
f.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) > 1 {
|
||||
// Format the allocs
|
||||
out := make([]string, len(allocs)+1)
|
||||
out[0] = "ID|Eval ID|Job ID|Task Group|Desired Status|Client Status"
|
||||
for i, alloc := range allocs {
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s",
|
||||
limit(alloc.ID, length),
|
||||
limit(alloc.EvalID, length),
|
||||
alloc.JobID,
|
||||
alloc.TaskGroup,
|
||||
alloc.DesiredStatus,
|
||||
alloc.ClientStatus,
|
||||
)
|
||||
}
|
||||
f.Ui.Output(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", formatList(out)))
|
||||
return 0
|
||||
}
|
||||
// Prefix lookup matched a single allocation
|
||||
alloc, _, err := client.Allocations().Info(allocs[0].ID, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if alloc.DesiredStatus == "failed" {
|
||||
allocID := limit(alloc.ID, length)
|
||||
msg := fmt.Sprintf(`The allocation %q failed to be placed. To see the cause, run:
|
||||
nomad alloc-status %s`, allocID, allocID)
|
||||
f.Ui.Error(msg)
|
||||
return 0
|
||||
}
|
||||
|
||||
// Get the contents of the file
|
||||
r, _, err := client.AllocFS().Cat(alloc, path, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error reading file: %v", err))
|
||||
return 1
|
||||
}
|
||||
io.Copy(os.Stdout, r)
|
||||
return 0
|
||||
}
|
172
command/fs_ls.go
172
command/fs_ls.go
|
@ -1,172 +0,0 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
type FSListCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (f *FSListCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: nomad fs ls <alloc-id> <path>
|
||||
|
||||
ls displays the contents of the allocation directory for the passed allocation. The path
|
||||
is relative to the root of the alloc dir and defaults to root if unspecified.
|
||||
|
||||
General Options:
|
||||
|
||||
` + generalOptionsUsage() + `
|
||||
|
||||
Ls Options:
|
||||
|
||||
-H
|
||||
Machine friendly output.
|
||||
|
||||
-verbose
|
||||
Show full information.
|
||||
|
||||
-job <job-id>
|
||||
Use a random allocation from a specified job-id.
|
||||
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (f *FSListCommand) Synopsis() string {
|
||||
return "List files in an allocation directory"
|
||||
}
|
||||
|
||||
func (f *FSListCommand) Run(args []string) int {
|
||||
var verbose bool
|
||||
var machine bool
|
||||
var job bool
|
||||
flags := f.Meta.FlagSet("fs-list", FlagSetClient)
|
||||
flags.Usage = func() { f.Ui.Output(f.Help()) }
|
||||
flags.BoolVar(&verbose, "verbose", false, "")
|
||||
flags.BoolVar(&machine, "H", false, "")
|
||||
flags.BoolVar(&job, "job", false, "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
args = flags.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
f.Ui.Error("allocation id is a required parameter")
|
||||
return 1
|
||||
}
|
||||
|
||||
path := "/"
|
||||
if len(args) == 2 {
|
||||
path = args[1]
|
||||
}
|
||||
|
||||
client, err := f.Meta.Client()
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error initializing client: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// If -job is specified, use random allocation, otherwise use provided allocation
|
||||
allocID := args[0]
|
||||
if job {
|
||||
allocID, err = getRandomJobAlloc(client, args[0])
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error fetching allocations: %v", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate the id unless full length is requested
|
||||
length := shortId
|
||||
if verbose {
|
||||
length = fullId
|
||||
}
|
||||
// Query the allocation info
|
||||
if len(allocID) == 1 {
|
||||
f.Ui.Error(fmt.Sprintf("Alloc ID must contain at least two characters."))
|
||||
return 1
|
||||
}
|
||||
if len(allocID)%2 == 1 {
|
||||
// Identifiers must be of even length, so we strip off the last byte
|
||||
// to provide a consistent user experience.
|
||||
allocID = allocID[:len(allocID)-1]
|
||||
}
|
||||
|
||||
allocs, _, err := client.Allocations().PrefixList(allocID)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) == 0 {
|
||||
f.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) > 1 {
|
||||
// Format the allocs
|
||||
out := make([]string, len(allocs)+1)
|
||||
out[0] = "ID|Eval ID|Job ID|Task Group|Desired Status|Client Status"
|
||||
for i, alloc := range allocs {
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s",
|
||||
limit(alloc.ID, length),
|
||||
limit(alloc.EvalID, length),
|
||||
alloc.JobID,
|
||||
alloc.TaskGroup,
|
||||
alloc.DesiredStatus,
|
||||
alloc.ClientStatus,
|
||||
)
|
||||
}
|
||||
f.Ui.Output(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", formatList(out)))
|
||||
return 0
|
||||
}
|
||||
// Prefix lookup matched a single allocation
|
||||
alloc, _, err := client.Allocations().Info(allocs[0].ID, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if alloc.DesiredStatus == "failed" {
|
||||
allocID := limit(alloc.ID, length)
|
||||
msg := fmt.Sprintf(`The allocation %q failed to be placed. To see the cause, run:
|
||||
nomad alloc-status %s`, allocID, allocID)
|
||||
f.Ui.Error(msg)
|
||||
return 0
|
||||
}
|
||||
// Get the file at the given path
|
||||
files, _, err := client.AllocFS().List(alloc, path, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error listing alloc dir: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
// Display the file information in a tabular format
|
||||
out := make([]string, len(files)+1)
|
||||
out[0] = "Mode|Size|Modfied Time|Name"
|
||||
for i, file := range files {
|
||||
fn := file.Name
|
||||
if file.IsDir {
|
||||
fn = fmt.Sprintf("%s/", fn)
|
||||
}
|
||||
var size string
|
||||
if machine {
|
||||
size = fmt.Sprintf("%d", file.Size)
|
||||
} else {
|
||||
size = humanize.Bytes(uint64(file.Size))
|
||||
}
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s",
|
||||
file.FileMode,
|
||||
size,
|
||||
formatTime(file.ModTime),
|
||||
fn,
|
||||
)
|
||||
}
|
||||
|
||||
f.Ui.Output(formatList(out))
|
||||
return 0
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
type FSStatCommand struct {
|
||||
Meta
|
||||
}
|
||||
|
||||
func (f *FSStatCommand) Help() string {
|
||||
helpText := `
|
||||
Usage: nomad fs stat <alloc-id> <path>
|
||||
|
||||
Displays information about an entry in an allocation directory at the given path.
|
||||
The path is relative to the allocation directory and defaults to root if unspecified.
|
||||
|
||||
General Options:
|
||||
|
||||
` + generalOptionsUsage() + `
|
||||
|
||||
Stat Options:
|
||||
|
||||
-H
|
||||
Machine friendly output.
|
||||
|
||||
-verbose
|
||||
Show full information.
|
||||
|
||||
-job <job-id>
|
||||
Use a random allocation from a specified job-id.
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
||||
func (f *FSStatCommand) Synopsis() string {
|
||||
return "Stat an entry in an allocation directory"
|
||||
}
|
||||
|
||||
func (f *FSStatCommand) Run(args []string) int {
|
||||
var verbose bool
|
||||
var machine bool
|
||||
var job bool
|
||||
flags := f.Meta.FlagSet("fs-list", FlagSetClient)
|
||||
flags.Usage = func() { f.Ui.Output(f.Help()) }
|
||||
flags.BoolVar(&verbose, "verbose", false, "")
|
||||
flags.BoolVar(&machine, "H", false, "")
|
||||
flags.BoolVar(&job, "job", false, "")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return 1
|
||||
}
|
||||
args = flags.Args()
|
||||
|
||||
if len(args) < 1 {
|
||||
f.Ui.Error("allocation id is a required parameter")
|
||||
return 1
|
||||
}
|
||||
|
||||
path := "/"
|
||||
if len(args) == 2 {
|
||||
path = args[1]
|
||||
}
|
||||
|
||||
client, err := f.Meta.Client()
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error initializing client: %v", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
allocID := args[0]
|
||||
if job {
|
||||
allocID, err = getRandomJobAlloc(client, args[0])
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying API: %v", err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate the id unless full length is requested
|
||||
length := shortId
|
||||
if verbose {
|
||||
length = fullId
|
||||
}
|
||||
// Query the allocation info
|
||||
if len(allocID) == 1 {
|
||||
f.Ui.Error(fmt.Sprintf("Alloc ID must contain at least two characters."))
|
||||
return 1
|
||||
}
|
||||
if len(allocID)%2 == 1 {
|
||||
// Identifiers must be of even length, so we strip off the last byte
|
||||
// to provide a consistent user experience.
|
||||
allocID = allocID[:len(allocID)-1]
|
||||
}
|
||||
|
||||
allocs, _, err := client.Allocations().PrefixList(allocID)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) == 0 {
|
||||
f.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID))
|
||||
return 1
|
||||
}
|
||||
if len(allocs) > 1 {
|
||||
// Format the allocs
|
||||
out := make([]string, len(allocs)+1)
|
||||
out[0] = "ID|Eval ID|Job ID|Task Group|Desired Status|Client Status"
|
||||
for i, alloc := range allocs {
|
||||
out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s",
|
||||
limit(alloc.ID, length),
|
||||
limit(alloc.EvalID, length),
|
||||
alloc.JobID,
|
||||
alloc.TaskGroup,
|
||||
alloc.DesiredStatus,
|
||||
alloc.ClientStatus,
|
||||
)
|
||||
}
|
||||
f.Ui.Output(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", formatList(out)))
|
||||
return 0
|
||||
}
|
||||
// Prefix lookup matched a single allocation
|
||||
alloc, _, err := client.Allocations().Info(allocs[0].ID, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if alloc.DesiredStatus == "failed" {
|
||||
allocID := limit(alloc.ID, length)
|
||||
msg := fmt.Sprintf(`The allocation %q failed to be placed. To see the cause, run:
|
||||
nomad alloc-status %s`, allocID, allocID)
|
||||
f.Ui.Error(msg)
|
||||
return 0
|
||||
}
|
||||
// Get the file information
|
||||
file, _, err := client.AllocFS().Stat(alloc, path, nil)
|
||||
if err != nil {
|
||||
f.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
||||
// Display the file information
|
||||
out := make([]string, 2)
|
||||
out[0] = "Mode|Size|Modified Time|Name"
|
||||
if file != nil {
|
||||
fn := file.Name
|
||||
if file.IsDir {
|
||||
fn = fmt.Sprintf("%s/", fn)
|
||||
}
|
||||
var size string
|
||||
if machine {
|
||||
size = fmt.Sprintf("%d", file.Size)
|
||||
} else {
|
||||
size = humanize.Bytes(uint64(file.Size))
|
||||
}
|
||||
out[1] = fmt.Sprintf("%s|%s|%s|%s", file.FileMode, size,
|
||||
formatTime(file.ModTime), fn)
|
||||
}
|
||||
f.Ui.Output(formatList(out))
|
||||
return 0
|
||||
}
|
23
commands.go
23
commands.go
|
@ -54,7 +54,6 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"eval-monitor": func() (cli.Command, error) {
|
||||
return &command.EvalMonitorCommand{
|
||||
Meta: meta,
|
||||
|
@ -70,21 +69,6 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"fs ls": func() (cli.Command, error) {
|
||||
return &command.FSListCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"fs stat": func() (cli.Command, error) {
|
||||
return &command.FSStatCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"fs cat": func() (cli.Command, error) {
|
||||
return &command.FSCatCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
"init": func() (cli.Command, error) {
|
||||
return &command.InitCommand{
|
||||
Meta: meta,
|
||||
|
@ -100,13 +84,11 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"node-status": func() (cli.Command, error) {
|
||||
return &command.NodeStatusCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"run": func() (cli.Command, error) {
|
||||
return &command.RunCommand{
|
||||
Meta: meta,
|
||||
|
@ -122,13 +104,11 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"server-join": func() (cli.Command, error) {
|
||||
return &command.ServerJoinCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"server-members": func() (cli.Command, error) {
|
||||
return &command.ServerMembersCommand{
|
||||
Meta: meta,
|
||||
|
@ -139,19 +119,16 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"stop": func() (cli.Command, error) {
|
||||
return &command.StopCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"validate": func() (cli.Command, error) {
|
||||
return &command.ValidateCommand{
|
||||
Meta: meta,
|
||||
}, nil
|
||||
},
|
||||
|
||||
"version": func() (cli.Command, error) {
|
||||
ver := Version
|
||||
rel := VersionPrerelease
|
||||
|
|
|
@ -8,19 +8,18 @@ description: >
|
|||
|
||||
# Command: fs
|
||||
|
||||
The `fs` family of commands allows a user to navigate an allocation directory on a Nomad
|
||||
client. The following subcommands are available - `cat`, `ls` and `stat`
|
||||
The `fs` command allows a user to navigate an allocation directory on a Nomad
|
||||
client. The following functionalities are available - `cat`, `ls` and `stat`
|
||||
|
||||
`cat`: Reads contents of files and writes them to the standard output.
|
||||
`ls`: Displays the name of a file and directories and their associated information.
|
||||
`stat`: Displays information about a file.
|
||||
`cat`: If the target path is a file, Nomad will cat the target path.
|
||||
`ls`: If the target path is a directory, Nomad displays the name of a file and directories and their associated information.
|
||||
`stat`: If the `-stat` flag is used, Nomad will Display information about a file.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
nomad fs ls <alloc-id> <path>
|
||||
nomad fs stat <alloc-id> <path>
|
||||
nomad fs cat <alloc-id> <path>
|
||||
nomad fs <alloc-id> <path>
|
||||
nomad fs -stat <alloc-id> <path>
|
||||
```
|
||||
|
||||
A valid allocation id is necessary unless `-job` is specified and the path is relative to the root of the allocation directory.
|
||||
|
@ -28,25 +27,25 @@ The path is optional and it defaults to `/` of the allocation directory
|
|||
|
||||
## Examples
|
||||
|
||||
$ nomad fs ls eb17e557
|
||||
$ nomad fs eb17e557
|
||||
Mode Size Modfied Time Name
|
||||
drwxrwxr-x 4096 28 Jan 16 05:39 UTC alloc/
|
||||
drwxrwxr-x 4096 28 Jan 16 05:39 UTC redis/
|
||||
-rw-rw-r-- 0 28 Jan 16 05:39 UTC redis_exit_status
|
||||
|
||||
|
||||
$ nomad fs ls redis/local
|
||||
$ nomad fs redis/local
|
||||
Mode Size Modfied Time Name
|
||||
-rw-rw-rw- 0 28 Jan 16 05:39 UTC redis.stderr
|
||||
-rw-rw-rw- 17 28 Jan 16 05:39 UTC redis.stdout
|
||||
|
||||
|
||||
$ nomad fs stat redis/local/redis.stdout
|
||||
$ nomad fs -stat redis/local/redis.stdout
|
||||
Mode Size Modified Time Name
|
||||
-rw-rw-rw- 17 28 Jan 16 05:39 UTC redis.stdout
|
||||
|
||||
|
||||
$ nomad fs cat redis/local/redis.stdout
|
||||
$ nomad fs redis/local/redis.stdout
|
||||
6710:C 27 Jan 22:04:03.794 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
|
||||
6710:M 27 Jan 22:04:03.795 * Increased maximum number of open files to 10032 (it was originally set to 256).
|
||||
|
||||
|
@ -55,7 +54,7 @@ $ nomad fs cat redis/local/redis.stdout
|
|||
Passing `-job` into one of the `fs` commands will allow the `fs` command to randomly select an allocation ID from the specified job.
|
||||
|
||||
```
|
||||
nomad fs ls -job <job-id> <path>
|
||||
nomad fs -job <job-id> <path>
|
||||
```
|
||||
|
||||
Nomad will prefer to select a running allocation ID for the job, but if no running allocations for the job are found, Nomad will use a dead allocation.
|
||||
|
|
Loading…
Reference in a new issue