diff --git a/.changelog/16478.txt b/.changelog/16478.txt new file mode 100644 index 000000000..f86be827e --- /dev/null +++ b/.changelog/16478.txt @@ -0,0 +1,3 @@ +```release-note:improvement +cli: Added `-json` flag to `quota inspect` command +``` diff --git a/api/util_test.go b/api/util_test.go index 76830693b..792dcfc82 100644 --- a/api/util_test.go +++ b/api/util_test.go @@ -102,7 +102,7 @@ func testNamespace() *Namespace { func testQuotaSpec() *QuotaSpec { return &QuotaSpec{ - Name: "test-namespace", + Name: "test-quota", Description: "Testing namespaces", Limits: []*QuotaLimit{ { diff --git a/command/quota_inspect.go b/command/quota_inspect.go index 1f0e7144e..483ce00b4 100644 --- a/command/quota_inspect.go +++ b/command/quota_inspect.go @@ -33,8 +33,11 @@ General Options: Inspect Options: + -json + Output the latest quota information in a JSON format. + -t - Format and display the namespaces using a Go template. + Format and display quota information using a Go template. ` return strings.TrimSpace(helpText) @@ -43,7 +46,8 @@ Inspect Options: func (c *QuotaInspectCommand) AutocompleteFlags() complete.Flags { return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient), complete.Flags{ - "-t": complete.PredictAnything, + "-t": complete.PredictAnything, + "-json": complete.PredictNothing, }) } @@ -58,9 +62,11 @@ func (c *QuotaInspectCommand) Synopsis() string { func (c *QuotaInspectCommand) Name() string { return "quota inspect" } func (c *QuotaInspectCommand) Run(args []string) int { + var json bool var tmpl string flags := c.Meta.FlagSet(c.Name(), FlagSetClient) flags.Usage = func() { c.Ui.Output(c.Help()) } + flags.BoolVar(&json, "json", false, "") flags.StringVar(&tmpl, "t", "", "") if err := flags.Parse(args); err != nil { @@ -97,6 +103,17 @@ func (c *QuotaInspectCommand) Run(args []string) int { return 1 } + if json || len(tmpl) > 0 { + out, err := Format(json, tmpl, spec) + if err != nil { + c.Ui.Error(err.Error()) + return 1 + } + + c.Ui.Output(out) + return 0 + } + // Get the quota usages usages, failures := quotaUsages(spec, quotas) @@ -111,7 +128,8 @@ func (c *QuotaInspectCommand) Run(args []string) int { Failures: failuresConverted, } - out, err := Format(len(tmpl) == 0, tmpl, data) + ftr := JSONFormat{} + out, err := ftr.TransformData(data) if err != nil { c.Ui.Error(err.Error()) return 1 diff --git a/command/quota_inspect_test.go b/command/quota_inspect_test.go index 73c941e07..e3f502133 100644 --- a/command/quota_inspect_test.go +++ b/command/quota_inspect_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/nomad/ci" "github.com/mitchellh/cli" "github.com/posener/complete" - "github.com/stretchr/testify/assert" + "github.com/shoenig/test/must" ) func TestQuotaInspectCommand_Implements(t *testing.T) { @@ -24,24 +24,20 @@ func TestQuotaInspectCommand_Fails(t *testing.T) { cmd := &QuotaInspectCommand{Meta: Meta{Ui: ui}} // Fails on misuse - if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 { - t.Fatalf("expected exit code 1, got: %d", code) - } - if out := ui.ErrorWriter.String(); !strings.Contains(out, commandErrorText(cmd)) { - t.Fatalf("expected help output, got: %s", out) - } + code = cmd.Run([]string{"some", "bad", "args"}) + must.One(t, code) + + must.StrContains(t, ui.ErrorWriter.String(), commandErrorText(cmd)) ui.ErrorWriter.Reset() - if code := cmd.Run([]string{"-address=nope", "foo"}); code != 1 { - t.Fatalf("expected exit code 1, got: %d", code) - } - if out := ui.ErrorWriter.String(); !strings.Contains(out, "retrieving quota") { - t.Fatalf("connection error, got: %s", out) - } + code = cmd.Run([]string{"-address=nope", "foo"}) + must.One(t, code) + + must.StrContains(t, ui.ErrorWriter.String(), "retrieving quota") ui.ErrorWriter.Reset() } -func TestQuotaInspectCommand_Good(t *testing.T) { +func TestQuotaInspectCommand_Run(t *testing.T) { ci.Parallel(t) // Create a server @@ -54,17 +50,34 @@ func TestQuotaInspectCommand_Good(t *testing.T) { // Create a quota to delete qs := testQuotaSpec() _, err := client.Quotas().Register(qs, nil) - assert.Nil(t, err) + must.NoError(t, err) - // Delete a namespace - if code := cmd.Run([]string{"-address=" + url, qs.Name}); code != 0 { - t.Fatalf("expected exit 0, got: %d; %v", code, ui.ErrorWriter.String()) - } + // Delete a quota + code := cmd.Run([]string{"-address=" + url, qs.Name}) + must.Zero(t, code) out := ui.OutputWriter.String() if !strings.Contains(out, "Usages") || !strings.Contains(out, qs.Name) { t.Fatalf("expected quota, got: %s", out) } + + // List json + must.Zero(t, cmd.Run([]string{"-address=" + url, "-json", allocID})) + + outJson := *api.Quotas{} + err = json.Unmarshal(ui.OutputWriter.Bytes(), &outJson) + must.NoError(t, err) + + ui.OutputWriter.Reset() + + // Go template to format the output + code = cmd.Run([]string{"-address=" + url, "-t", "{{ .Name }}", allocID}) + must.Zero(t, code) + + out = ui.OutputWriter.String() + must.StrContains(t, out, "test-quota") + + ui.OutputWriter.Reset() } func TestQuotaInspectCommand_AutocompleteArgs(t *testing.T) { @@ -80,12 +93,12 @@ func TestQuotaInspectCommand_AutocompleteArgs(t *testing.T) { // Create a quota qs := testQuotaSpec() _, err := client.Quotas().Register(qs, nil) - assert.Nil(err) + must.NoError(t, err) args := complete.Args{Last: "t"} predictor := cmd.AutocompleteArgs() res := predictor.Predict(args) - assert.Equal(1, len(res)) - assert.Equal(qs.Name, res[0]) + must.One(t, len(res)) + must.StrContains(t, qs.Name, res[0]) } diff --git a/website/content/docs/commands/quota/inspect.mdx b/website/content/docs/commands/quota/inspect.mdx index a2239ceb0..97aaa16bb 100644 --- a/website/content/docs/commands/quota/inspect.mdx +++ b/website/content/docs/commands/quota/inspect.mdx @@ -29,7 +29,9 @@ capability and access to any namespaces that the quota is applied to. ## Inspect Options -- `-t` : Format and display the quota using a Go template. +- `-json`: Output the quota specifications in a JSON format. + +- `-t`: Format and display the quota using a Go template. ## Examples @@ -88,3 +90,34 @@ $ nomad quota inspect default-quota } } ``` + +The `-json` flag can be used to get the quota specs in json format: +```shell-session +$ nomad quota inspect -json default-quota + +{ + "CreateIndex": 8, + "Description": "Limit the shared default namespace", + "Limits": [ + { + "Hash": "NLOoV2WBU8ieJIrYXXx8NRb5C2xU61pVVWRDLEIMxlU=", + "Region": "global", + "RegionLimit": { + "CPU": 2500, + "DiskMB": 0, + "MemoryMB": 2000, + "Networks": null + } + } + ], + "ModifyIndex": 56, + "Name": "default-quota" +} +``` + +Or use the `-t` flag to format and display the quota specs using a Go template: +```shell-session +$ nomad quota inspect -t {{ .Description }} default-quota + +Limit the shared default namespace +```