diff --git a/api/hosts/create.gen.go b/api/hosts/create.gen.go index aba4400c6..2f3950000 100644 --- a/api/hosts/create.gen.go +++ b/api/hosts/create.gen.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/watchtower/api" ) -func (s HostCatalog) CreateHost(ctx context.Context, host *Host) (*Host, *api.Error, error) { +func (s HostCatalog) CreateHost(ctx context.Context, r *Host) (*Host, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in CreateHost request") } @@ -22,7 +22,7 @@ func (s HostCatalog) CreateHost(ctx context.Context, host *Host) (*Host, *api.Er } - req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/hosts", s.Id), host) + req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/hosts", s.Id), r) if err != nil { return nil, nil, fmt.Errorf("error creating CreateHost request: %w", err) } @@ -43,7 +43,7 @@ func (s HostCatalog) CreateHost(ctx context.Context, host *Host) (*Host, *api.Er return target, apiErr, nil } -func (s HostCatalog) CreateHostSet(ctx context.Context, hostset *HostSet) (*HostSet, *api.Error, error) { +func (s HostCatalog) CreateHostSet(ctx context.Context, r *HostSet) (*HostSet, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in CreateHostSet request") } @@ -57,7 +57,7 @@ func (s HostCatalog) CreateHostSet(ctx context.Context, hostset *HostSet) (*Host } - req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets", s.Id), hostset) + req, err := s.Client.NewRequest(ctx, "POST", fmt.Sprintf("host-catalogs/%s/host-sets", s.Id), r) if err != nil { return nil, nil, fmt.Errorf("error creating CreateHostSet request: %w", err) } diff --git a/api/hosts/host_catalog_test.go b/api/hosts/host_catalog_test.go new file mode 100644 index 000000000..f100753c3 --- /dev/null +++ b/api/hosts/host_catalog_test.go @@ -0,0 +1,108 @@ +package hosts_test + +import ( + "net/http" + "testing" + + "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/hosts" + "github.com/hashicorp/watchtower/api/scopes" + "github.com/hashicorp/watchtower/internal/host/static" + "github.com/hashicorp/watchtower/internal/servers/controller" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCatalogs_Crud(t *testing.T) { + tc := controller.NewTestController(t, nil) + defer tc.Shutdown() + + client := tc.Client() + org := &scopes.Organization{ + Client: client, + } + p, apiErr, err := org.CreateProject(tc.Context(), &scopes.Project{}) + require.NoError(t, err) + require.Nil(t, apiErr) + require.NotNil(t, p) + + checkCatalog := func(step string, hc *hosts.HostCatalog, apiErr *api.Error, err error, wantedName string) { + assert := assert.New(t) + assert.NoError(err, step) + if !assert.Nil(apiErr, step) && apiErr.Message != nil { + t.Errorf("ApiError message: %q", *apiErr.Message) + } + assert.NotNil(hc, "returned project", step) + gotName := "" + if hc.Name != nil { + gotName = *hc.Name + } + assert.Equal(wantedName, gotName, step) + } + + hc, apiErr, err := p.CreateHostCatalog(tc.Context(), &hosts.HostCatalog{Name: api.String("foo"), Type: api.String("Static")}) + checkCatalog("create", hc, apiErr, err, "foo") + + hc, apiErr, err = p.ReadHostCatalog(tc.Context(), &hosts.HostCatalog{Id: hc.Id}) + checkCatalog("read", hc, apiErr, err, "foo") + + hc = &hosts.HostCatalog{Id: hc.Id} + hc.Name = api.String("bar") + hc, apiErr, err = p.UpdateHostCatalog(tc.Context(), hc) + checkCatalog("update", hc, apiErr, err, "bar") + + hc = &hosts.HostCatalog{Id: hc.Id} + hc.SetDefault("name") + hc, apiErr, err = p.UpdateHostCatalog(tc.Context(), hc) + checkCatalog("update", hc, apiErr, err, "") + + existed, apiErr, err := p.DeleteHostCatalog(tc.Context(), hc) + assert.NoError(t, err) + assert.True(t, existed, "Expected existing catalog when deleted, but it wasn't.") + + existed, apiErr, err = p.DeleteHostCatalog(tc.Context(), hc) + assert.NoError(t, err) + assert.False(t, existed, "Expected catalog to not exist when deleted, but it did.") +} + +// TODO: Get better coverage for expected errors and error formats. +func TestProject_Errors(t *testing.T) { + assert := assert.New(t) + tc := controller.NewTestController(t, nil) + defer tc.Shutdown() + ctx := tc.Context() + + client := tc.Client() + org := &scopes.Organization{ + Client: client, + } + p, apiErr, err := org.CreateProject(ctx, &scopes.Project{}) + assert.NoError(err) + assert.NotNil(p) + assert.Nil(apiErr) + + hc, apiErr, err := p.CreateHostCatalog(ctx, &hosts.HostCatalog{Type: api.String("Static")}) + assert.NoError(err) + assert.Nil(apiErr) + assert.NotNil(hc) + + _, apiErr, err = p.CreateHostCatalog(ctx, &hosts.HostCatalog{}) + assert.NoError(err) + assert.NotNil(apiErr) + + _, apiErr, err = p.ReadHostCatalog(ctx, &hosts.HostCatalog{Id: static.HostCatalogPrefix + "_doesntexis"}) + assert.NoError(err) + // TODO: Should this be nil instead of just a catalog that has no values set + assert.NotNil(apiErr) + assert.EqualValues(*apiErr.Status, http.StatusNotFound) + + _, apiErr, err = p.ReadHostCatalog(ctx, &hosts.HostCatalog{Id: "invalid id"}) + assert.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(*apiErr.Status, http.StatusBadRequest) + + _, apiErr, err = p.UpdateHostCatalog(ctx, &hosts.HostCatalog{Id: hc.Id, Type: api.String("Cant Update")}) + assert.NoError(err) + assert.NotNil(apiErr) + assert.EqualValues(*apiErr.Status, http.StatusBadRequest) +} diff --git a/api/internal/genapi/create.go b/api/internal/genapi/create.go index 9846bd296..b03d690af 100644 --- a/api/internal/genapi/create.go +++ b/api/internal/genapi/create.go @@ -18,21 +18,26 @@ type createInfo struct { var createFuncs = map[string][]*createInfo{ "hosts": { { - "HostCatalog", - "Host", - `fmt.Sprintf("host-catalogs/%s/hosts", s.Id)`, + baseType: "HostCatalog", + targetType: "Host", + path: `fmt.Sprintf("host-catalogs/%s/hosts", s.Id)`, }, { - "HostCatalog", - "HostSet", - `fmt.Sprintf("host-catalogs/%s/host-sets", s.Id)`, + baseType: "HostCatalog", + targetType: "HostSet", + path: `fmt.Sprintf("host-catalogs/%s/host-sets", s.Id)`, }, }, "scopes": { { - "Organization", - "Project", - `"projects"`, + baseType: "Organization", + targetType: "Project", + path: `"projects"`, + }, + { + baseType: "Project", + targetType: "hosts.HostCatalog", + path: `"host-catalogs"`, }, }, } @@ -46,15 +51,15 @@ package %s `, outPkg))) for _, createInfo := range funcs { createFuncTemplate.Execute(outBuf, struct { - BaseType string - TargetType string - LowerTargetType string - Path string + BaseType string + TargetType string + TargetName string + Path string }{ - BaseType: createInfo.baseType, - TargetType: createInfo.targetType, - LowerTargetType: strings.ToLower(createInfo.targetType), - Path: createInfo.path, + BaseType: createInfo.baseType, + TargetType: createInfo.targetType, + TargetName: strings.Split(createInfo.targetType, ".")[strings.Count(createInfo.targetType, ".")], + Path: createInfo.path, }) } if err := ioutil.WriteFile(outFile, outBuf.Bytes(), 0644); err != nil { @@ -66,7 +71,7 @@ package %s var createFuncTemplate = template.Must(template.New("").Parse( ` -func (s {{ .BaseType }}) Create{{ .TargetType }}(ctx context.Context, {{ .LowerTargetType }} *{{ .TargetType }}) (*{{ .TargetType }}, *api.Error, error) { +func (s {{ .BaseType }}) Create{{ .TargetName }}(ctx context.Context, r *{{ .TargetType }}) (*{{ .TargetType }}, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in Create{{ .TargetType }} request") } @@ -90,7 +95,7 @@ func (s {{ .BaseType }}) Create{{ .TargetType }}(ctx context.Context, {{ .LowerT {{ end }} } - req, err := s.Client.NewRequest(ctx, "POST", {{ .Path }}, {{ .LowerTargetType }}) + req, err := s.Client.NewRequest(ctx, "POST", {{ .Path }}, r) if err != nil { return nil, nil, fmt.Errorf("error creating Create{{ .TargetType }} request: %w", err) } diff --git a/api/internal/genapi/delete.go b/api/internal/genapi/delete.go index 50b7ab079..0574b5a81 100644 --- a/api/internal/genapi/delete.go +++ b/api/internal/genapi/delete.go @@ -20,7 +20,12 @@ var deleteFuncs = map[string][]*deleteInfo{ { "Organization", "Project", - "projects/%s", + "projects", + }, + { + "Project", + "hosts.HostCatalog", + "host-catalogs", }, }, } @@ -34,15 +39,15 @@ package %s `, outPkg))) for _, deleteInfo := range funcs { deleteFuncTemplate.Execute(outBuf, struct { - BaseType string - TargetType string - LowerTargetType string - Path string + BaseType string + TargetType string + TargetName string + Path string }{ - BaseType: deleteInfo.baseType, - TargetType: deleteInfo.targetType, - LowerTargetType: strings.ToLower(deleteInfo.targetType), - Path: deleteInfo.path, + BaseType: deleteInfo.baseType, + TargetType: deleteInfo.targetType, + TargetName: strings.Split(deleteInfo.targetType, ".")[strings.Count(deleteInfo.targetType, ".")], + Path: deleteInfo.path, }) } if err := ioutil.WriteFile(outFile, outBuf.Bytes(), 0644); err != nil { @@ -54,10 +59,10 @@ package %s var deleteFuncTemplate = template.Must(template.New("").Parse( ` -// Delete{{ .TargetType }} returns true iff the {{ .LowerTargetType }} existed when the delete attempt was made. -func (s {{ .BaseType }}) Delete{{ .TargetType }}(ctx context.Context, {{ .LowerTargetType }} *{{ .TargetType }}) (bool, *api.Error, error) { +// Delete{{ .TargetName }} returns true iff the {{ .TargetType }} existed when the delete attempt was made. +func (s {{ .BaseType }}) Delete{{ .TargetName }}(ctx context.Context, r *{{ .TargetType }}) (bool, *api.Error, error) { if s.Client == nil { - return false, nil, fmt.Errorf("nil client in Delete{{ .TargetType }} request") + return false, nil, fmt.Errorf("nil client in Delete{{ .TargetName }} request") } if s.Id == "" { {{ if (eq .BaseType "Organization") }} @@ -67,7 +72,7 @@ func (s {{ .BaseType }}) Delete{{ .TargetType }}(ctx context.Context, {{ .LowerT // Assume the client has been configured with project already and move // on {{ else }} - return nil, nil, fmt.Errorf("missing {{ .BaseType }} ID in Delete{{ .TargetType }} request") + return nil, nil, fmt.Errorf("missing {{ .BaseType }} ID in Delete{{ .TargetName }} request") {{ end }} } else { // If it's explicitly set here, override anything that might be in the @@ -78,18 +83,18 @@ func (s {{ .BaseType }}) Delete{{ .TargetType }}(ctx context.Context, {{ .LowerT ctx = context.WithValue(ctx, "project", s.Id) {{ end }} } - if {{ .LowerTargetType }}.Id == "" { - return false, nil, fmt.Errorf("empty {{ .LowerTargetType }} ID field in Delete{{ .TargetType }} request") + if r.Id == "" { + return false, nil, fmt.Errorf("empty {{ .TargetType }} ID field in Delete{{ .TargetName }} request") } - req, err := s.Client.NewRequest(ctx, "DELETE", fmt.Sprintf("{{ .Path }}", {{ .LowerTargetType }}.Id), nil) + req, err := s.Client.NewRequest(ctx, "DELETE", fmt.Sprintf("%s/%s", "{{ .Path }}", r.Id), nil) if err != nil { - return false, nil, fmt.Errorf("error creating Delete{{ .TargetType }} request: %w", err) + return false, nil, fmt.Errorf("error creating Delete{{ .TargetName }} request: %w", err) } resp, err := s.Client.Do(req) if err != nil { - return false, nil, fmt.Errorf("error performing client request during Delete{{ .TargetType }} call: %w", err) + return false, nil, fmt.Errorf("error performing client request during Delete{{ .TargetName }} call: %w", err) } type deleteResponse struct { @@ -99,7 +104,7 @@ func (s {{ .BaseType }}) Delete{{ .TargetType }}(ctx context.Context, {{ .LowerT apiErr, err := resp.Decode(target) if err != nil { - return false, nil, fmt.Errorf("error decoding Delete{{ .TargetType }} repsonse: %w", err) + return false, nil, fmt.Errorf("error decoding Delete{{ .TargetName }} repsonse: %w", err) } return target.Existed, apiErr, nil diff --git a/api/internal/genapi/read.go b/api/internal/genapi/read.go index ae6850426..7fcd23806 100644 --- a/api/internal/genapi/read.go +++ b/api/internal/genapi/read.go @@ -12,17 +12,20 @@ import ( type readInfo struct { baseType string targetType string - verb string path string } var readFuncs = map[string][]*readInfo{ "scopes": { { - "Organization", - "Project", - "GET", - "projects/%s", + baseType: "Organization", + targetType: "Project", + path: "projects", + }, + { + baseType: "Project", + targetType: "hosts.HostCatalog", + path: "host-catalogs", }, }, } @@ -36,17 +39,15 @@ package %s `, outPkg))) for _, readInfo := range funcs { readFuncTemplate.Execute(outBuf, struct { - BaseType string - TargetType string - LowerTargetType string - Verb string - Path string + BaseType string + TargetType string + TargetName string + Path string }{ - BaseType: readInfo.baseType, - TargetType: readInfo.targetType, - LowerTargetType: strings.ToLower(readInfo.targetType), - Verb: readInfo.verb, - Path: readInfo.path, + BaseType: readInfo.baseType, + TargetType: readInfo.targetType, + TargetName: strings.Split(readInfo.targetType, ".")[strings.Count(readInfo.targetType, ".")], + Path: readInfo.path, }) } if err := ioutil.WriteFile(outFile, outBuf.Bytes(), 0644); err != nil { @@ -58,9 +59,9 @@ package %s var readFuncTemplate = template.Must(template.New("").Parse( ` -func (s {{ .BaseType }}) Read{{ .TargetType }}(ctx context.Context, {{ .LowerTargetType }} *{{ .TargetType }}) (*{{ .TargetType }}, *api.Error, error) { +func (s {{ .BaseType }}) Read{{ .TargetName }}(ctx context.Context, r *{{ .TargetType }}) (*{{ .TargetType }}, *api.Error, error) { if s.Client == nil { - return nil, nil, fmt.Errorf("nil client in Read{{ .TargetType }} request") + return nil, nil, fmt.Errorf("nil client in Read{{ .TargetName }} request") } if s.Id == "" { {{ if (eq .BaseType "Organization") }} @@ -81,24 +82,24 @@ func (s {{ .BaseType }}) Read{{ .TargetType }}(ctx context.Context, {{ .LowerTar ctx = context.WithValue(ctx, "project", s.Id) {{ end }} } - if {{ .LowerTargetType }}.Id == "" { - return nil, nil, fmt.Errorf("empty {{ .LowerTargetType }} ID field in Read{{ .TargetType }} request") + if r.Id == "" { + return nil, nil, fmt.Errorf("empty {{ .TargetType }} ID field in Read{{ .TargetName }} request") } - req, err := s.Client.NewRequest(ctx, "{{ .Verb }}", fmt.Sprintf("{{ .Path }}", {{ .LowerTargetType }}.Id), {{ .LowerTargetType }}) + req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "{{ .Path }}", r.Id), r) if err != nil { - return nil, nil, fmt.Errorf("error creating Read{{ .TargetType }} request: %w", err) + return nil, nil, fmt.Errorf("error creating Read{{ .TargetName }} request: %w", err) } resp, err := s.Client.Do(req) if err != nil { - return nil, nil, fmt.Errorf("error performing client request during Read{{ .TargetType }} call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Read{{ .TargetName }} call: %w", err) } target := new({{ .TargetType }}) apiErr, err := resp.Decode(target) if err != nil { - return nil, nil, fmt.Errorf("error decoding Read{{ .TargetType }} repsonse: %w", err) + return nil, nil, fmt.Errorf("error decoding Read{{ .TargetName }} repsonse: %w", err) } {{ if (eq .TargetType "Organization") }} diff --git a/api/internal/genapi/update.go b/api/internal/genapi/update.go index 3688fabd2..61e9a7ffc 100644 --- a/api/internal/genapi/update.go +++ b/api/internal/genapi/update.go @@ -18,9 +18,14 @@ type updateInfo struct { var updateFuncs = map[string][]*updateInfo{ "scopes": { { - "Organization", - "Project", - "projects/%s", + baseType: "Organization", + targetType: "Project", + path: "projects", + }, + { + baseType: "Project", + targetType: "hosts.HostCatalog", + path: "host-catalogs", }, }, } @@ -34,15 +39,15 @@ package %s `, outPkg))) for _, updateInfo := range funcs { updateFuncTemplate.Execute(outBuf, struct { - BaseType string - TargetType string - LowerTargetType string - Path string + BaseType string + TargetType string + TargetName string + Path string }{ - BaseType: updateInfo.baseType, - TargetType: updateInfo.targetType, - LowerTargetType: strings.ToLower(updateInfo.targetType), - Path: updateInfo.path, + BaseType: updateInfo.baseType, + TargetType: updateInfo.targetType, + TargetName: strings.Split(updateInfo.targetType, ".")[strings.Count(updateInfo.targetType, ".")], + Path: updateInfo.path, }) } if err := ioutil.WriteFile(outFile, outBuf.Bytes(), 0644); err != nil { @@ -54,9 +59,9 @@ package %s var updateFuncTemplate = template.Must(template.New("").Parse( ` -func (s {{ .BaseType }}) Update{{ .TargetType }}(ctx context.Context, {{ .LowerTargetType }} *{{ .TargetType }}) (*{{ .TargetType }}, *api.Error, error) { +func (s {{ .BaseType }}) Update{{ .TargetName }}(ctx context.Context, r *{{ .TargetType }}) (*{{ .TargetType }}, *api.Error, error) { if s.Client == nil { - return nil, nil, fmt.Errorf("nil client in Create{{ .TargetType }} request") + return nil, nil, fmt.Errorf("nil client in Create{{ .TargetName }} request") } if s.Id == "" { {{ if (eq .BaseType "Organization") }} @@ -66,7 +71,7 @@ func (s {{ .BaseType }}) Update{{ .TargetType }}(ctx context.Context, {{ .LowerT // Assume the client has been configured with project already and move // on {{ else }} - return nil, nil, fmt.Errorf("missing {{ .BaseType}} ID in Create{{ .TargetType }} request") + return nil, nil, fmt.Errorf("missing {{ .BaseType}} ID in Create{{ .TargetName }} request") {{ end }} } else { // If it's explicitly set here, override anything that might be in the @@ -78,23 +83,23 @@ func (s {{ .BaseType }}) Update{{ .TargetType }}(ctx context.Context, {{ .LowerT {{ end }} } - id := {{ .LowerTargetType }}.Id - {{ .LowerTargetType }}.Id = "" + id := r.Id + r.Id = "" - req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("{{ .Path }}", id), {{ .LowerTargetType }}) + req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("%s/%s", "{{ .Path }}", id), r) if err != nil { - return nil, nil, fmt.Errorf("error creating Create{{ .TargetType }} request: %w", err) + return nil, nil, fmt.Errorf("error creating Create{{ .TargetName }} request: %w", err) } resp, err := s.Client.Do(req) if err != nil { - return nil, nil, fmt.Errorf("error performing client request during Update{{ .TargetType }} call: %w", err) + return nil, nil, fmt.Errorf("error performing client request during Update{{ .TargetName }} call: %w", err) } target := new({{ .TargetType }}) apiErr, err := resp.Decode(target) if err != nil { - return nil, nil, fmt.Errorf("error decoding Update{{ .TargetType }} repsonse: %w", err) + return nil, nil, fmt.Errorf("error decoding Update{{ .TargetName }} repsonse: %w", err) } {{ if (eq .TargetType "Organization") }} diff --git a/api/scopes/create.gen.go b/api/scopes/create.gen.go index 5c092a8ee..0f80adcc8 100644 --- a/api/scopes/create.gen.go +++ b/api/scopes/create.gen.go @@ -6,9 +6,10 @@ import ( "fmt" "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/hosts" ) -func (s Organization) CreateProject(ctx context.Context, project *Project) (*Project, *api.Error, error) { +func (s Organization) CreateProject(ctx context.Context, r *Project) (*Project, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in CreateProject request") } @@ -25,7 +26,7 @@ func (s Organization) CreateProject(ctx context.Context, project *Project) (*Pro } - req, err := s.Client.NewRequest(ctx, "POST", "projects", project) + req, err := s.Client.NewRequest(ctx, "POST", "projects", r) if err != nil { return nil, nil, fmt.Errorf("error creating CreateProject request: %w", err) } @@ -46,3 +47,41 @@ func (s Organization) CreateProject(ctx context.Context, project *Project) (*Pro return target, apiErr, nil } + +func (s Project) CreateHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in Createhosts.HostCatalog request") + } + if s.Id == "" { + + // Assume the client has been configured with project already and move + // on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "project", s.Id) + + } + + req, err := s.Client.NewRequest(ctx, "POST", "host-catalogs", r) + if err != nil { + return nil, nil, fmt.Errorf("error creating Createhosts.HostCatalog request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during Createhosts.HostCatalog call: %w", err) + } + + target := new(hosts.HostCatalog) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding Createhosts.HostCatalog repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} diff --git a/api/scopes/delete.gen.go b/api/scopes/delete.gen.go index 2dab01a0b..978ae062b 100644 --- a/api/scopes/delete.gen.go +++ b/api/scopes/delete.gen.go @@ -6,10 +6,11 @@ import ( "fmt" "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/hosts" ) -// DeleteProject returns true iff the project existed when the delete attempt was made. -func (s Organization) DeleteProject(ctx context.Context, project *Project) (bool, *api.Error, error) { +// DeleteProject returns true iff the Project existed when the delete attempt was made. +func (s Organization) DeleteProject(ctx context.Context, r *Project) (bool, *api.Error, error) { if s.Client == nil { return false, nil, fmt.Errorf("nil client in DeleteProject request") } @@ -25,11 +26,11 @@ func (s Organization) DeleteProject(ctx context.Context, project *Project) (bool ctx = context.WithValue(ctx, "org", s.Id) } - if project.Id == "" { - return false, nil, fmt.Errorf("empty project ID field in DeleteProject request") + if r.Id == "" { + return false, nil, fmt.Errorf("empty Project ID field in DeleteProject request") } - req, err := s.Client.NewRequest(ctx, "DELETE", fmt.Sprintf("projects/%s", project.Id), nil) + req, err := s.Client.NewRequest(ctx, "DELETE", fmt.Sprintf("%s/%s", "projects", r.Id), nil) if err != nil { return false, nil, fmt.Errorf("error creating DeleteProject request: %w", err) } @@ -51,3 +52,47 @@ func (s Organization) DeleteProject(ctx context.Context, project *Project) (bool return target.Existed, apiErr, nil } + +// DeleteHostCatalog returns true iff the hosts.HostCatalog existed when the delete attempt was made. +func (s Project) DeleteHostCatalog(ctx context.Context, r *hosts.HostCatalog) (bool, *api.Error, error) { + if s.Client == nil { + return false, nil, fmt.Errorf("nil client in DeleteHostCatalog request") + } + if s.Id == "" { + + // Assume the client has been configured with project already and move + // on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "project", s.Id) + + } + if r.Id == "" { + return false, nil, fmt.Errorf("empty hosts.HostCatalog ID field in DeleteHostCatalog request") + } + + req, err := s.Client.NewRequest(ctx, "DELETE", fmt.Sprintf("%s/%s", "host-catalogs", r.Id), nil) + if err != nil { + return false, nil, fmt.Errorf("error creating DeleteHostCatalog request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return false, nil, fmt.Errorf("error performing client request during DeleteHostCatalog call: %w", err) + } + + type deleteResponse struct { + Existed bool + } + target := &deleteResponse{} + + apiErr, err := resp.Decode(target) + if err != nil { + return false, nil, fmt.Errorf("error decoding DeleteHostCatalog repsonse: %w", err) + } + + return target.Existed, apiErr, nil +} diff --git a/api/scopes/project_test.go b/api/scopes/project_test.go index 93fa25642..ecc02dc2e 100644 --- a/api/scopes/project_test.go +++ b/api/scopes/project_test.go @@ -1,10 +1,11 @@ -package scopes +package scopes_test import ( "net/http" "testing" "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/scopes" "github.com/hashicorp/watchtower/internal/servers/controller" "github.com/stretchr/testify/assert" ) @@ -14,29 +15,38 @@ func TestProjects_Crud(t *testing.T) { defer tc.Shutdown() client := tc.Client() - org := &Organization{ + org := &scopes.Organization{ Client: client, } - checkProject := func(step string, p *Project, apiErr *api.Error, err error, wantedName string) { + checkProject := func(step string, p *scopes.Project, apiErr *api.Error, err error, wantedName string) { assert := assert.New(t) assert.NoError(err, step) assert.Nil(apiErr, step) assert.NotNil(p, "returned project", step) - assert.Equal(wantedName, *p.Name, step) + gotName := "" + if p.Name != nil { + gotName = *p.Name + } + assert.Equal(wantedName, gotName, step) } - p, apiErr, err := org.CreateProject(tc.Context(), &Project{Name: api.String("foo")}) + p, apiErr, err := org.CreateProject(tc.Context(), &scopes.Project{Name: api.String("foo")}) checkProject("create", p, apiErr, err, "foo") - p, apiErr, err = org.ReadProject(tc.Context(), &Project{Id: p.Id}) + p, apiErr, err = org.ReadProject(tc.Context(), &scopes.Project{Id: p.Id}) checkProject("read", p, apiErr, err, "foo") - p = &Project{Id: p.Id} + p = &scopes.Project{Id: p.Id} p.Name = api.String("bar") p, apiErr, err = org.UpdateProject(tc.Context(), p) checkProject("update", p, apiErr, err, "bar") + p = &scopes.Project{Id: p.Id} + p.SetDefault("name") + p, apiErr, err = org.UpdateProject(tc.Context(), p) + checkProject("update, unset name", p, apiErr, err, "") + existed, apiErr, err := org.DeleteProject(tc.Context(), p) assert.NoError(t, err) assert.True(t, existed, "Expected existing project when deleted, but it wasn't.") @@ -54,21 +64,21 @@ func TestProject_Errors(t *testing.T) { ctx := tc.Context() client := tc.Client() - org := &Organization{ + org := &scopes.Organization{ Client: client, } - createdProj, apiErr, err := org.CreateProject(ctx, &Project{}) + createdProj, apiErr, err := org.CreateProject(ctx, &scopes.Project{}) assert.NoError(err) assert.NotNil(createdProj) assert.Nil(apiErr) - _, apiErr, err = org.ReadProject(ctx, &Project{Id: "p_doesntexis"}) + _, apiErr, err = org.ReadProject(ctx, &scopes.Project{Id: "p_doesntexis"}) assert.NoError(err) // TODO: Should this be nil instead of just a Project that has no values set assert.NotNil(apiErr) assert.EqualValues(*apiErr.Status, http.StatusNotFound) - _, apiErr, err = org.ReadProject(ctx, &Project{Id: "invalid id"}) + _, apiErr, err = org.ReadProject(ctx, &scopes.Project{Id: "invalid id"}) assert.NoError(err) assert.NotNil(apiErr) assert.EqualValues(*apiErr.Status, http.StatusBadRequest) diff --git a/api/scopes/read.gen.go b/api/scopes/read.gen.go index 0dc80071a..151983dc0 100644 --- a/api/scopes/read.gen.go +++ b/api/scopes/read.gen.go @@ -6,9 +6,10 @@ import ( "fmt" "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/hosts" ) -func (s Organization) ReadProject(ctx context.Context, project *Project) (*Project, *api.Error, error) { +func (s Organization) ReadProject(ctx context.Context, r *Project) (*Project, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in ReadProject request") } @@ -24,11 +25,11 @@ func (s Organization) ReadProject(ctx context.Context, project *Project) (*Proje ctx = context.WithValue(ctx, "org", s.Id) } - if project.Id == "" { - return nil, nil, fmt.Errorf("empty project ID field in ReadProject request") + if r.Id == "" { + return nil, nil, fmt.Errorf("empty Project ID field in ReadProject request") } - req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("projects/%s", project.Id), project) + req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "projects", r.Id), r) if err != nil { return nil, nil, fmt.Errorf("error creating ReadProject request: %w", err) } @@ -49,3 +50,44 @@ func (s Organization) ReadProject(ctx context.Context, project *Project) (*Proje return target, apiErr, nil } + +func (s Project) ReadHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in ReadHostCatalog request") + } + if s.Id == "" { + + // Assume the client has been configured with project already and move + // on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "project", s.Id) + + } + if r.Id == "" { + return nil, nil, fmt.Errorf("empty hosts.HostCatalog ID field in ReadHostCatalog request") + } + + req, err := s.Client.NewRequest(ctx, "GET", fmt.Sprintf("%s/%s", "host-catalogs", r.Id), r) + if err != nil { + return nil, nil, fmt.Errorf("error creating ReadHostCatalog request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during ReadHostCatalog call: %w", err) + } + + target := new(hosts.HostCatalog) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding ReadHostCatalog repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +} diff --git a/api/scopes/update.gen.go b/api/scopes/update.gen.go index a003819e3..27fba7cf7 100644 --- a/api/scopes/update.gen.go +++ b/api/scopes/update.gen.go @@ -6,9 +6,10 @@ import ( "fmt" "github.com/hashicorp/watchtower/api" + "github.com/hashicorp/watchtower/api/hosts" ) -func (s Organization) UpdateProject(ctx context.Context, project *Project) (*Project, *api.Error, error) { +func (s Organization) UpdateProject(ctx context.Context, r *Project) (*Project, *api.Error, error) { if s.Client == nil { return nil, nil, fmt.Errorf("nil client in CreateProject request") } @@ -25,10 +26,10 @@ func (s Organization) UpdateProject(ctx context.Context, project *Project) (*Pro } - id := project.Id - project.Id = "" + id := r.Id + r.Id = "" - req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("projects/%s", id), project) + req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("%s/%s", "projects", id), r) if err != nil { return nil, nil, fmt.Errorf("error creating CreateProject request: %w", err) } @@ -49,3 +50,44 @@ func (s Organization) UpdateProject(ctx context.Context, project *Project) (*Pro return target, apiErr, nil } + +func (s Project) UpdateHostCatalog(ctx context.Context, r *hosts.HostCatalog) (*hosts.HostCatalog, *api.Error, error) { + if s.Client == nil { + return nil, nil, fmt.Errorf("nil client in CreateHostCatalog request") + } + if s.Id == "" { + + // Assume the client has been configured with project already and move + // on + + } else { + // If it's explicitly set here, override anything that might be in the + // client + + ctx = context.WithValue(ctx, "project", s.Id) + + } + + id := r.Id + r.Id = "" + + req, err := s.Client.NewRequest(ctx, "PATCH", fmt.Sprintf("%s/%s", "host-catalogs", id), r) + if err != nil { + return nil, nil, fmt.Errorf("error creating CreateHostCatalog request: %w", err) + } + + resp, err := s.Client.Do(req) + if err != nil { + return nil, nil, fmt.Errorf("error performing client request during UpdateHostCatalog call: %w", err) + } + + target := new(hosts.HostCatalog) + apiErr, err := resp.Decode(target) + if err != nil { + return nil, nil, fmt.Errorf("error decoding UpdateHostCatalog repsonse: %w", err) + } + + target.Client = s.Client + + return target, apiErr, nil +}