Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: show name in resolve-name-status table #567

Merged
merged 5 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions cmd/appliance/resolve_name_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ import (
)

type resolveNameStatusOpts struct {
Config *configuration.Config
Out io.Writer
Client func(c *configuration.Config) (*openapi.APIClient, error)
Appliance func(c *configuration.Config) (*appliancepkg.Appliance, error)
debug bool
json bool
applianceID string
Config *configuration.Config
Out io.Writer
Client func(c *configuration.Config) (*openapi.APIClient, error)
Appliance func(c *configuration.Config) (*appliancepkg.Appliance, error)
withPartials bool
debug bool
json bool
applianceID string
}

func NewResolveNameStatusCmd(f *factory.Factory) *cobra.Command {
Expand Down Expand Up @@ -82,16 +83,17 @@ func NewResolveNameStatusCmd(f *factory.Factory) *cobra.Command {
return nil
},
RunE: func(c *cobra.Command, args []string) error {
return resolveNameStatusRun(c, args, &opts)
return resolveNameStatusRun(&opts)
},
}
cmd.Flags().BoolVar(&opts.withPartials, "partial-resolution", false, "include all partial resolutions in table")
cmd.Flags().BoolVar(&opts.json, "json", false, "Display in JSON format")
cmd.SetHelpFunc(cmdutil.HideIncludeExcludeFlags)

return cmd
}

func resolveNameStatusRun(cmd *cobra.Command, args []string, opts *resolveNameStatusOpts) error {
func resolveNameStatusRun(opts *resolveNameStatusOpts) error {
client, err := opts.Client(opts.Config)
if err != nil {
return err
Expand All @@ -111,9 +113,16 @@ func resolveNameStatusRun(cmd *cobra.Command, args []string, opts *resolveNameSt
}

p := util.NewPrinter(opts.Out, 4)
p.AddHeader("Partial", "Finals", "Partials", "Errors")
for _, r := range result.GetResolutions() {
p.AddLine(r.GetPartial(), r.GetFinals(), r.GetPartials(), r.GetErrors())
if opts.withPartials {
p.AddHeader("Name", "Final Resolutions", "Partial Resolution", "Errors", "Partials")
for k, r := range result.GetResolutions() {
p.AddLine(k, r.GetFinals(), r.GetPartial(), r.GetErrors(), r.GetPartials())
}
} else {
p.AddHeader("Name", "Final Resolutions", "Partial Resolution", "Errors")
for k, r := range result.GetResolutions() {
p.AddLine(k, r.GetFinals(), r.GetPartial(), r.GetErrors())
}
}
p.Print()
return nil
Expand Down
106 changes: 99 additions & 7 deletions cmd/appliance/resolve_name_status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,108 @@ import (
"testing"

"github.com/appgate/sdp-api-client-go/api/v20/openapi"
"github.com/appgate/sdpctl/pkg/appliance"
appliancepkg "github.com/appgate/sdpctl/pkg/appliance"
"github.com/appgate/sdpctl/pkg/configuration"
"github.com/appgate/sdpctl/pkg/factory"
"github.com/appgate/sdpctl/pkg/httpmock"
"github.com/appgate/sdpctl/pkg/util"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
)

func TestResolveNameStatusCMD(t *testing.T) {
tests := []struct {
name, appliance, cli, want string
wantErr bool
wantErrOut *regexp.Regexp
}{
{
name: "basic name resolution status test",
appliance: appliancepkg.TestAppliancePrimary,
want: `Name Final Resolutions Partial Resolution Errors
---- ----------------- ------------------ ------
aws://lb-tag:kubernetes.io/service-name=opsnonprod/erp-dev [3.120.51.78 35.156.237.184] false []
`,
},
{
name: "name resolution status table with partials",
cli: "--partial-resolution",
appliance: appliancepkg.TestAppliancePrimary,
want: `Name Final Resolutions Partial Resolution Errors Partials
---- ----------------- ------------------ ------ --------
aws://lb-tag:kubernetes.io/service-name=opsnonprod/erp-dev [3.120.51.78 35.156.237.184] false [] [dns://all.GW-ELB-2001535196.eu-central-1.elb.amazonaws.com dns://all.purple-lb-1785267452.eu-central-1.elb.amazonaws.com]
`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
registry := httpmock.NewRegistry(t)
hostname := "appgate.test"
coll := appliancepkg.GenerateCollective(t, hostname, "6.3", "", []string{tt.appliance})
appliance := coll.Appliances[tt.appliance]
for _, stub := range coll.GenerateStubs(coll.GetAppliances(), *coll.Stats, *coll.UpgradedStats) {
registry.RegisterStub(stub)
}
defer registry.Teardown()
registry.Serve()

stdout := &bytes.Buffer{}
stdin := &bytes.Buffer{}
stderr := &bytes.Buffer{}
in := io.NopCloser(stdin)
f := &factory.Factory{
Config: &configuration.Config{
Debug: false,
URL: fmt.Sprintf("http://%s:%d/admin", hostname, registry.Port),
},
IOOutWriter: stdout,
Stdin: in,
StdErr: stderr,
}
f.APIClient = func(c *configuration.Config) (*openapi.APIClient, error) {
return registry.Client, nil
}
f.Appliance = func(c *configuration.Config) (*appliancepkg.Appliance, error) {
api, _ := f.APIClient(c)

a := &appliancepkg.Appliance{
APIClient: api,
HTTPClient: api.GetConfig().HTTPClient,
Token: "",
}
return a, nil
}
args := []string{appliance.GetId()}
if len(tt.cli) > 0 {
args = append(args, tt.cli)
}
cmd := NewResolveNameStatusCmd(f)
cmd.SetArgs(args)
cmd.PersistentFlags().Bool("descending", false, "")
cmd.PersistentFlags().StringSlice("order-by", []string{"name"}, "")
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)

_, err := cmd.ExecuteC()
if (err != nil) != tt.wantErr {
t.Fatalf("NewResolveNameStatusCmd() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil && tt.wantErrOut != nil {
if !tt.wantErrOut.MatchString(err.Error()) {
t.Errorf("Expected output to match, got:\n%s\n expected: \n%s\n", tt.wantErrOut, err.Error())
}
return
}
body, err := io.ReadAll(stdout)
if err != nil {
t.Fatalf("unable to read stdout %s", err)
}
got := string(body)
assert.Equal(t, tt.want, got)
})
}
}

func TestNewResolveNameStatusCmdJSON(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -83,10 +177,10 @@ func TestNewResolveNameStatusCmdJSON(t *testing.T) {
f.APIClient = func(c *configuration.Config) (*openapi.APIClient, error) {
return registry.Client, nil
}
f.Appliance = func(c *configuration.Config) (*appliance.Appliance, error) {
f.Appliance = func(c *configuration.Config) (*appliancepkg.Appliance, error) {
api, _ := f.APIClient(c)

a := &appliance.Appliance{
a := &appliancepkg.Appliance{
APIClient: api,
HTTPClient: api.GetConfig().HTTPClient,
Token: "",
Expand Down Expand Up @@ -136,9 +230,7 @@ func TestNewResolveNameStatusCmdJSON(t *testing.T) {
}
}
`
if diff := cmp.Diff(want, got, httpmock.TransformJSONFilter); diff != "" {
t.Fatalf("JSON Diff (-want +got):\n%s", diff)
}
assert.Equal(t, want, got)
})
}
}
5 changes: 3 additions & 2 deletions docs/sdpctl_appliance_functions_download.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ <h2 class="text-left margin-bottom">sdpctl appliance functions download</h2><p>D
&gt; sdpctl appliance functions download LogServer --docker-registry=&lt;path-to-custom-docker-registry&gt;
</code></pre>
<hr class="margin-bottom"><h3 class="emphasize text-left margin-bottom-small">Options</h3>
<pre class="code-editor margin-bottom"><code> --docker-registry string docker registry for downloading image bundles
<pre class="code-editor margin-bottom"><code> --destination string path to a directory where the container bundle should be saved. The command will create a directory if it doesn't already exist (default &quot;$HOME/Downloads/appgate&quot;)
--docker-registry string docker registry for downloading image bundles
-h, --help help for download
--save-path string path to where the container bundle should be saved (default &quot;$HOME/Downloads/appgate&quot;)
--save-path string [DEPRECATED, use '--destination' instead] path to a directory where the container bundle should be saved. The command will create a directory if it doesn't already exist
--version string Override the LogServer version that will be downloaded. Defaults to the same version as the primary controller.
</code></pre>
<hr class="margin-bottom"><h3 class="emphasize text-left margin-bottom-small">Options inherited from parent commands</h3>
Expand Down
5 changes: 3 additions & 2 deletions docs/sdpctl_appliance_resolve-name-status.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ <h2 class="text-left margin-bottom">sdpctl appliance resolve-name-status</h2><p>
}
</code></pre>
<hr class="margin-bottom"><h3 class="emphasize text-left margin-bottom-small">Options</h3>
<pre class="code-editor margin-bottom"><code> -h, --help help for resolve-name-status
--json Display in JSON format
<pre class="code-editor margin-bottom"><code> -h, --help help for resolve-name-status
--json Display in JSON format
--partial-resolution include all partial resolutions in table
</code></pre>
<hr class="margin-bottom"><h3 class="emphasize text-left margin-bottom-small">Options inherited from parent commands</h3>
<pre class="code-editor margin-bottom"><code> --api-version int Peer API version override
Expand Down
30 changes: 30 additions & 0 deletions pkg/appliance/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ var (
}
)

func (cts *CollectiveTestStruct) GetAppliances() []openapi.Appliance {
a := make([]openapi.Appliance, 0, len(cts.Appliances))
for _, app := range cts.Appliances {
a = append(a, app)
}
return a
}

func (cts *CollectiveTestStruct) GenerateStubs(appliances []openapi.Appliance, stats, upgradedStats openapi.StatsAppliancesList) []httpmock.Stub {
stubs := []httpmock.Stub{}

Expand Down Expand Up @@ -291,6 +299,28 @@ func (cts *CollectiveTestStruct) GenerateStubs(appliances []openapi.Appliance, s
URL: fmt.Sprintf("/admin/appliances/%s/backup/%s", a.GetId(), backupID),
Responder: httpmock.FileResponse(),
})

stubs = append(stubs, httpmock.Stub{
URL: fmt.Sprintf("/admin/appliances/%s/name-resolution-status", a.GetId()),
Responder: func(w http.ResponseWriter, r *http.Request) {
res := openapi.NewAppliancesIdNameResolutionStatusGet200ResponseWithDefaults()
res.Resolutions = &map[string]openapi.AppliancesIdNameResolutionStatusGet200ResponseResolutionsValue{
"aws://lb-tag:kubernetes.io/service-name=opsnonprod/erp-dev": {
Partial: openapi.PtrBool(false),
Finals: []string{"3.120.51.78", "35.156.237.184"},
Partials: []string{"dns://all.GW-ELB-2001535196.eu-central-1.elb.amazonaws.com", "dns://all.purple-lb-1785267452.eu-central-1.elb.amazonaws.com"},
Errors: []string{},
},
}
b, err := res.MarshalJSON()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
w.Write(b)
},
})
}

return stubs
Expand Down
5 changes: 0 additions & 5 deletions pkg/httpmock/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,6 @@ func NewRegistry(t *testing.T) *Registry {
os.Setenv("SDPCTL_BEARER", "header-token-value")
t.Cleanup(func() {
t.Helper()
for _, s := range r.stubs {
if !s.matched {
t.Logf("URL %s was registered but never used", s.URL)
}
}
for _, notFound := range r.notFound {
t.Logf("%s was not registered, but requested", notFound)
}
Expand Down
Loading