github.com/ryanslade/nomad@v0.2.4-0.20160128061903-fc95782f2089/command/fs_cat.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "strings" 8 ) 9 10 type FSCatCommand struct { 11 Meta 12 } 13 14 func (f *FSCatCommand) Help() string { 15 helpText := ` 16 Usage: nomad fs-cat <alloc-id> <path> 17 18 Dispays a file in an allocation directory at the given path. 19 The path is relative to the allocation directory and defaults to root if unspecified. 20 21 General Options: 22 23 ` + generalOptionsUsage() + ` 24 25 -verbose 26 Show full information. 27 ` 28 return strings.TrimSpace(helpText) 29 } 30 31 func (f *FSCatCommand) Synopsis() string { 32 return "displays a file at a given location" 33 } 34 35 func (f *FSCatCommand) Run(args []string) int { 36 var verbose bool 37 flags := f.Meta.FlagSet("fs-list", FlagSetClient) 38 flags.Usage = func() { f.Ui.Output(f.Help()) } 39 flags.BoolVar(&verbose, "verbose", false, "") 40 41 if err := flags.Parse(args); err != nil { 42 return 1 43 } 44 args = flags.Args() 45 46 if len(args) < 1 { 47 f.Ui.Error("allocation id is a required parameter") 48 return 1 49 } 50 51 allocID := args[0] 52 path := "/" 53 if len(args) == 2 { 54 path = args[1] 55 } 56 57 client, err := f.Meta.Client() 58 if err != nil { 59 f.Ui.Error(fmt.Sprintf("Error inititalizing client: %v", err)) 60 return 1 61 } 62 63 // Truncate the id unless full length is requested 64 length := shortId 65 if verbose { 66 length = fullId 67 } 68 // Query the allocation info 69 alloc, _, err := client.Allocations().Info(allocID, nil) 70 if err != nil { 71 if len(allocID) == 1 { 72 f.Ui.Error(fmt.Sprintf("Alloc ID must contain at least two characters.")) 73 return 1 74 } 75 if len(allocID)%2 == 1 { 76 // Identifiers must be of even length, so we strip off the last byte 77 // to provide a consistent user experience. 78 allocID = allocID[:len(allocID)-1] 79 } 80 81 allocs, _, err := client.Allocations().PrefixList(allocID) 82 if err != nil { 83 f.Ui.Error(fmt.Sprintf("Error querying allocation: %v", err)) 84 return 1 85 } 86 if len(allocs) == 0 { 87 f.Ui.Error(fmt.Sprintf("No allocation(s) with prefix or id %q found", allocID)) 88 return 1 89 } 90 if len(allocs) > 1 { 91 // Format the allocs 92 out := make([]string, len(allocs)+1) 93 out[0] = "ID|Eval ID|Job ID|Task Group|Desired Status|Client Status" 94 for i, alloc := range allocs { 95 out[i+1] = fmt.Sprintf("%s|%s|%s|%s|%s|%s", 96 limit(alloc.ID, length), 97 limit(alloc.EvalID, length), 98 alloc.JobID, 99 alloc.TaskGroup, 100 alloc.DesiredStatus, 101 alloc.ClientStatus, 102 ) 103 } 104 f.Ui.Output(fmt.Sprintf("Prefix matched multiple allocations\n\n%s", formatList(out))) 105 return 0 106 } 107 // Prefix lookup matched a single allocation 108 alloc, _, err = client.Allocations().Info(allocs[0].ID, nil) 109 if err != nil { 110 f.Ui.Error(fmt.Sprintf("Error querying allocation: %s", err)) 111 return 1 112 } 113 } 114 115 // Stat the file to find it's size 116 file, _, err := client.AllocFS().Stat(alloc, path, nil) 117 if err != nil { 118 f.Ui.Error(err.Error()) 119 return 1 120 } 121 if file.IsDir { 122 f.Ui.Error(fmt.Sprintf("The file %q is a directory", file.Name)) 123 return 1 124 } 125 126 // Get the contents of the file 127 offset := 0 128 limit := file.Size 129 r, _, err := client.AllocFS().ReadAt(alloc, path, int64(offset), limit, nil) 130 if err != nil { 131 f.Ui.Error(fmt.Sprintf("Error reading file: %v", err)) 132 return 1 133 } 134 io.Copy(os.Stdout, r) 135 return 0 136 }