github.com/uchennaokeke444/nomad@v0.11.8/command/volume_status_csi.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/nomad/api"
     9  	"github.com/hashicorp/nomad/nomad/structs"
    10  )
    11  
    12  func (c *VolumeStatusCommand) csiBanner() {
    13  	if !(c.json || len(c.template) > 0) {
    14  		c.Ui.Output(c.Colorize().Color("[bold]Container Storage Interface[reset]"))
    15  	}
    16  }
    17  
    18  func (c *VolumeStatusCommand) csiStatus(client *api.Client, id string) int {
    19  	// Invoke list mode if no volume id
    20  	if id == "" {
    21  		c.csiBanner()
    22  		vols, _, err := client.CSIVolumes().List(nil)
    23  		if err != nil {
    24  			c.Ui.Error(fmt.Sprintf("Error querying volumes: %s", err))
    25  			return 1
    26  		}
    27  
    28  		if len(vols) == 0 {
    29  			// No output if we have no volumes
    30  			c.Ui.Error("No CSI volumes")
    31  		} else {
    32  			str, err := c.csiFormatVolumes(vols)
    33  			if err != nil {
    34  				c.Ui.Error(fmt.Sprintf("Error formatting: %s", err))
    35  				return 1
    36  			}
    37  			c.Ui.Output(str)
    38  		}
    39  		return 0
    40  	}
    41  
    42  	// Try querying the volume
    43  	vol, _, err := client.CSIVolumes().Info(id, nil)
    44  	if err != nil {
    45  		c.Ui.Error(fmt.Sprintf("Error querying volume: %s", err))
    46  		return 1
    47  	}
    48  
    49  	str, err := c.formatBasic(vol)
    50  	if err != nil {
    51  		c.Ui.Error(fmt.Sprintf("Error formatting volume: %s", err))
    52  		return 1
    53  	}
    54  	c.Ui.Output(str)
    55  
    56  	return 0
    57  }
    58  
    59  func (c *VolumeStatusCommand) csiFormatVolumes(vols []*api.CSIVolumeListStub) (string, error) {
    60  	// Sort the output by volume id
    61  	sort.Slice(vols, func(i, j int) bool { return vols[i].ID < vols[j].ID })
    62  
    63  	if c.json || len(c.template) > 0 {
    64  		out, err := Format(c.json, c.template, vols)
    65  		if err != nil {
    66  			return "", fmt.Errorf("format error: %v", err)
    67  		}
    68  		return out, nil
    69  	}
    70  
    71  	rows := make([]string, len(vols)+1)
    72  	rows[0] = "ID|Name|Plugin ID|Schedulable|Access Mode"
    73  	for i, v := range vols {
    74  		rows[i+1] = fmt.Sprintf("%s|%s|%s|%t|%s",
    75  			limit(v.ID, c.length),
    76  			v.Name,
    77  			v.PluginID,
    78  			v.Schedulable,
    79  			v.AccessMode,
    80  		)
    81  	}
    82  	return formatList(rows), nil
    83  }
    84  
    85  func (c *VolumeStatusCommand) formatBasic(vol *api.CSIVolume) (string, error) {
    86  	if c.json || len(c.template) > 0 {
    87  		out, err := Format(c.json, c.template, vol)
    88  		if err != nil {
    89  			return "", fmt.Errorf("format error: %v", err)
    90  		}
    91  		return out, nil
    92  	}
    93  
    94  	output := []string{
    95  		fmt.Sprintf("ID|%s", vol.ID),
    96  		fmt.Sprintf("Name|%s", vol.Name),
    97  		fmt.Sprintf("External ID|%s", vol.ExternalID),
    98  		fmt.Sprintf("Plugin ID|%s", vol.PluginID),
    99  		fmt.Sprintf("Provider|%s", vol.Provider),
   100  		fmt.Sprintf("Version|%s", vol.ProviderVersion),
   101  		fmt.Sprintf("Schedulable|%t", vol.Schedulable),
   102  		fmt.Sprintf("Controllers Healthy|%d", vol.ControllersHealthy),
   103  		fmt.Sprintf("Controllers Expected|%d", vol.ControllersExpected),
   104  		fmt.Sprintf("Nodes Healthy|%d", vol.NodesHealthy),
   105  		fmt.Sprintf("Nodes Expected|%d", vol.NodesExpected),
   106  
   107  		fmt.Sprintf("Access Mode|%s", vol.AccessMode),
   108  		fmt.Sprintf("Attachment Mode|%s", vol.AttachmentMode),
   109  		fmt.Sprintf("Mount Options|%s", csiVolMountOption(vol.MountOptions, nil)),
   110  		fmt.Sprintf("Namespace|%s", vol.Namespace),
   111  	}
   112  
   113  	// Exit early
   114  	if c.short {
   115  		return formatKV(output), nil
   116  	}
   117  
   118  	// Format the allocs
   119  	banner := c.Colorize().Color("\n[bold]Allocations[reset]")
   120  	allocs := formatAllocListStubs(vol.Allocations, c.verbose, c.length)
   121  	full := []string{formatKV(output), banner, allocs}
   122  	return strings.Join(full, "\n"), nil
   123  }
   124  
   125  func (c *VolumeStatusCommand) formatTopologies(vol *api.CSIVolume) string {
   126  	var out []string
   127  
   128  	// Find the union of all the keys
   129  	head := map[string]string{}
   130  	for _, t := range vol.Topologies {
   131  		for key := range t.Segments {
   132  			if _, ok := head[key]; !ok {
   133  				head[key] = ""
   134  			}
   135  		}
   136  	}
   137  
   138  	// Append the header
   139  	var line []string
   140  	for key := range head {
   141  		line = append(line, key)
   142  	}
   143  	out = append(out, strings.Join(line, " "))
   144  
   145  	// Append each topology
   146  	for _, t := range vol.Topologies {
   147  		line = []string{}
   148  		for key := range head {
   149  			line = append(line, t.Segments[key])
   150  		}
   151  		out = append(out, strings.Join(line, " "))
   152  	}
   153  
   154  	return strings.Join(out, "\n")
   155  }
   156  
   157  func csiVolMountOption(volume, request *api.CSIMountOptions) string {
   158  	var req, opts *structs.CSIMountOptions
   159  
   160  	if request != nil {
   161  		req = &structs.CSIMountOptions{
   162  			FSType:     request.FSType,
   163  			MountFlags: request.MountFlags,
   164  		}
   165  	}
   166  
   167  	if volume == nil {
   168  		opts = req
   169  	} else {
   170  		opts = &structs.CSIMountOptions{
   171  			FSType:     volume.FSType,
   172  			MountFlags: volume.MountFlags,
   173  		}
   174  		opts.Merge(req)
   175  	}
   176  
   177  	if opts == nil {
   178  		return "<none>"
   179  	}
   180  
   181  	var out string
   182  	if opts.FSType != "" {
   183  		out = fmt.Sprintf("fs_type: %s", opts.FSType)
   184  	}
   185  
   186  	if len(opts.MountFlags) > 0 {
   187  		out = fmt.Sprintf("%s flags: %s", out, strings.Join(opts.MountFlags, ", "))
   188  	}
   189  
   190  	return out
   191  }