Delete actions for plugin based catalogs and sets (#1622)
* Add ability to delete plugin based host catalogs and host sets * Add plugin host catalog and set tests for API.
This commit is contained in:
12 files changed
+745
-34
No files matched your search
@@ -1,21 +1,14 @@
|
||||
module github.com/hashicorp/boundary
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
replace github.com/hashicorp/boundary/api => ./api
|
||||
|
||||
replace github.com/hashicorp/boundary/sdk => ./sdk
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go v57.4.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.21 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/armon/go-metrics v0.3.9
|
||||
github.com/aws/aws-sdk-go v1.40.44 // indirect
|
||||
github.com/bufbuild/buf v0.37.0
|
||||
github.com/dhui/dktest v0.3.4 // indirect
|
||||
github.com/fatih/color v1.12.0
|
||||
github.com/fatih/structs v1.1.0
|
||||
github.com/favadi/protoc-go-inject-tag v1.3.0
|
||||
@@ -24,7 +17,7 @@ require (
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/go-cmp v0.5.6
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0
|
||||
github.com/hashicorp/boundary/api v0.0.19
|
||||
github.com/hashicorp/boundary/sdk v0.0.12-0.20211007161358-65f3725bf3e1
|
||||
@@ -40,7 +33,6 @@ require (
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0
|
||||
github.com/hashicorp/go-rootcerts v1.0.2
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.4 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/base62 v0.1.1
|
||||
github.com/hashicorp/go-secure-stdlib/configutil v0.1.2
|
||||
github.com/hashicorp/go-secure-stdlib/gatedwriter v0.1.1
|
||||
@@ -52,7 +44,6 @@ require (
|
||||
github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1
|
||||
github.com/hashicorp/go-uuid v1.0.2
|
||||
github.com/hashicorp/go-version v1.3.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/hashicorp/vault/api v1.1.1
|
||||
github.com/hashicorp/vault/sdk v0.2.1
|
||||
@@ -77,7 +68,6 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/posener/complete v1.2.3
|
||||
github.com/ryanuber/go-glob v1.0.0
|
||||
github.com/spf13/cobra v1.1.1 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/zalando/go-keyring v0.1.1
|
||||
go.uber.org/atomic v1.9.0
|
||||
@@ -85,7 +75,6 @@ require (
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678
|
||||
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf
|
||||
golang.org/x/tools v0.1.6
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83
|
||||
google.golang.org/grpc v1.40.0
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
|
||||
@@ -95,3 +84,132 @@ require (
|
||||
mvdan.cc/gofumpt v0.1.1
|
||||
nhooyr.io/websocket v1.8.7
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.65.0 // indirect
|
||||
github.com/AlecAivazis/survey/v2 v2.2.9 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v57.4.0+incompatible // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.21 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.14 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/Microsoft/go-winio v0.4.16 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f // indirect
|
||||
github.com/apex/log v1.9.0 // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.40.44 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.0 // indirect
|
||||
github.com/containerd/continuity v0.0.0-20200709052629-daa8e1ccc0bc // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.0.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/danieljoos/wincred v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dhui/dktest v0.3.4 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/cli v20.10.7+incompatible // indirect
|
||||
github.com/docker/docker v20.10.7+incompatible // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/gofrs/flock v0.8.0 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.0.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
|
||||
github.com/hashicorp/go-plugin v1.0.1 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.4 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.1 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/go-version v1.3.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.3 // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.1.1 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.7.0 // indirect
|
||||
github.com/jefferai/go-libsecret v0.0.0-20210105015933-d08a58b018bc // indirect
|
||||
github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f // indirect
|
||||
github.com/jhump/protoreflect v1.8.1 // indirect
|
||||
github.com/jinzhu/gorm v1.9.12 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.2 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.10 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect
|
||||
github.com/klauspost/compress v1.11.7 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/lib/pq v1.8.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
github.com/mitchellh/iochan v1.0.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/mtibben/percent v0.2.1 // indirect
|
||||
github.com/oklog/run v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v1.0.0-rc9 // indirect
|
||||
github.com/oracle/oci-go-sdk v12.5.0+incompatible // indirect
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
|
||||
github.com/pkg/profile v1.5.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.6.2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||
github.com/spf13/cobra v1.1.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/twitchtv/twirp v7.1.0+incompatible // indirect
|
||||
github.com/urfave/cli/v2 v2.3.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
go.opencensus.io v0.22.6 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.16.0 // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/api v0.30.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/ini.v1 v1.51.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
@@ -195,6 +195,80 @@ func (r *Repository) ListCatalogs(ctx context.Context, scopeIds []string, opt ..
|
||||
return hostCatalogs, plgs, nil
|
||||
}
|
||||
|
||||
// DeleteCatalog deletes catalog for the provided id from the repository
|
||||
// returning a count of the number of records deleted. All options are ignored.
|
||||
func (r *Repository) DeleteCatalog(ctx context.Context, id string, _ ...Option) (int, error) {
|
||||
const op = "plugin.(Repository).DeleteCatalog"
|
||||
if id == "" {
|
||||
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
|
||||
c, err := r.getCatalog(ctx, id)
|
||||
if err != nil && !errors.IsNotFoundError(err) {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if c == nil {
|
||||
return db.NoRowsAffected, nil
|
||||
}
|
||||
p, err := r.getPersistedDataForCatalog(ctx, c)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
plgClient, ok := r.plugins[c.GetPluginId()]
|
||||
if !ok || plgClient == nil {
|
||||
return 0, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("plugin %q not available", c.GetPluginId()))
|
||||
}
|
||||
plgHc, err := toPluginCatalog(ctx, c)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
// TODO: Include all the sets for this catalog in the delete catalog request. We don't need it for now
|
||||
// since our currently provided plugins only read data for set configuration, but in the future that might
|
||||
// change.
|
||||
_, err = plgClient.OnDeleteCatalog(ctx, &plgpb.OnDeleteCatalogRequest{Catalog: plgHc, Persisted: p})
|
||||
if err != nil {
|
||||
// Even if the plugin returns an error, we ignore it and proceed with
|
||||
// deleting the catalog.
|
||||
}
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, c.ScopeId, kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
}
|
||||
metadata := c.oplog(oplog.OpType_OP_TYPE_DELETE)
|
||||
|
||||
var rowsDeleted int
|
||||
var deleteCatalog *HostCatalog
|
||||
_, err = r.writer.DoTx(
|
||||
ctx,
|
||||
db.StdRetryCnt,
|
||||
db.ExpBackoff{},
|
||||
func(_ db.Reader, w db.Writer) error {
|
||||
deleteCatalog = c.clone()
|
||||
var err error
|
||||
rowsDeleted, err = w.Delete(
|
||||
ctx,
|
||||
deleteCatalog,
|
||||
db.WithOplog(oplogWrapper, metadata),
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("delete failed for %s", c.PublicId)))
|
||||
}
|
||||
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
// getCatalog retrieves the *HostCatalog with the provided id. If it is not found or there
|
||||
// is an problem getting it from the database an error is returned instead.
|
||||
func (r *Repository) getCatalog(ctx context.Context, id string) (*HostCatalog, error) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -470,3 +471,154 @@ func TestRepository_ListCatalogs_Multiple_Scopes(t *testing.T) {
|
||||
assert.Equal(t, total, len(got))
|
||||
assert.Contains(t, plgs, plg)
|
||||
}
|
||||
|
||||
func TestRepository_DeleteCatalog(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
plg := hostplg.TestPlugin(t, conn, "test")
|
||||
pluginInstance := &TestPluginServer{}
|
||||
plgm := map[string]plgpb.HostPluginServiceClient{
|
||||
plg.GetPublicId(): &WrappingPluginClient{Server: pluginInstance},
|
||||
}
|
||||
cat := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
cat2 := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
badId, err := newHostCatalogId(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, badId)
|
||||
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, repo)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
id string
|
||||
pluginChecker func(*testing.T, *plgpb.OnDeleteCatalogRequest) error
|
||||
want int
|
||||
wantErr errors.Code
|
||||
}{
|
||||
{
|
||||
name: "found",
|
||||
id: cat.GetPublicId(),
|
||||
pluginChecker: func(t *testing.T, req *plgpb.OnDeleteCatalogRequest) error {
|
||||
assert.Equal(t, cat.GetPublicId(), req.GetCatalog().GetId())
|
||||
return nil
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "ignore error",
|
||||
id: cat2.GetPublicId(),
|
||||
pluginChecker: func(t *testing.T, req *plgpb.OnDeleteCatalogRequest) error {
|
||||
assert.Equal(t, cat2.GetPublicId(), req.GetCatalog().GetId())
|
||||
return fmt.Errorf("This is a test error")
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "not-found",
|
||||
id: badId,
|
||||
pluginChecker: func(t *testing.T, req *plgpb.OnDeleteCatalogRequest) error {
|
||||
assert.Fail(t, "Should not call the plugin when catalog isn't found")
|
||||
return nil
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "bad-public-id",
|
||||
id: "",
|
||||
pluginChecker: func(t *testing.T, req *plgpb.OnDeleteCatalogRequest) error {
|
||||
assert.Fail(t, "Should not call the plugin for a bad id")
|
||||
return nil
|
||||
},
|
||||
want: 0,
|
||||
wantErr: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pluginInstance.OnDeleteCatalogFn = func(_ context.Context, request *plgpb.OnDeleteCatalogRequest) (*plgpb.OnDeleteCatalogResponse, error) {
|
||||
return nil, tt.pluginChecker(t, request)
|
||||
}
|
||||
got, err := repo.DeleteCatalog(context.Background(), tt.id)
|
||||
if tt.wantErr != 0 {
|
||||
assert.Truef(t, errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, got, "row count")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepository_DeleteCatalogX(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
_, prj := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
plg := hostplg.TestPlugin(t, conn, "test")
|
||||
plgm := map[string]plgpb.HostPluginServiceClient{
|
||||
plg.GetPublicId(): &WrappingPluginClient{Server: &TestPluginServer{}},
|
||||
}
|
||||
cat := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
badId, err := newHostCatalogId(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, badId)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
id string
|
||||
want *HostCatalog
|
||||
wantErr errors.Code
|
||||
}{
|
||||
{
|
||||
name: "found",
|
||||
id: cat.GetPublicId(),
|
||||
want: cat,
|
||||
},
|
||||
{
|
||||
name: "not-found",
|
||||
id: badId,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "bad-public-id",
|
||||
id: "",
|
||||
want: nil,
|
||||
wantErr: errors.InvalidParameter,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(err)
|
||||
assert.NotNil(repo)
|
||||
|
||||
got, _, err := repo.LookupCatalog(ctx, tt.id)
|
||||
if tt.wantErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantErr), err), "want err: %q got: %q", tt.wantErr, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(err)
|
||||
|
||||
switch {
|
||||
case tt.want == nil:
|
||||
assert.Nil(got)
|
||||
case tt.want != nil:
|
||||
assert.NotNil(got)
|
||||
assert.Equal(got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -249,6 +249,85 @@ func (r *Repository) ListSets(ctx context.Context, catalogId string, opt ...host
|
||||
return sets, plg, nil
|
||||
}
|
||||
|
||||
// DeleteSet deletes the host set for the provided id from the repository
|
||||
// returning a count of the number of records deleted. All options are
|
||||
// ignored.
|
||||
func (r *Repository) DeleteSet(ctx context.Context, scopeId string, publicId string, _ ...Option) (int, error) {
|
||||
const op = "plugin.(Repository).DeleteSet"
|
||||
if publicId == "" {
|
||||
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "no public id")
|
||||
}
|
||||
if scopeId == "" {
|
||||
return db.NoRowsAffected, errors.New(ctx, errors.InvalidParameter, op, "no scope id")
|
||||
}
|
||||
|
||||
sets, plg, err := r.getSets(ctx, publicId, "")
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if len(sets) != 1 {
|
||||
return db.NoRowsAffected, nil
|
||||
}
|
||||
s := sets[0]
|
||||
|
||||
c, err := r.getCatalog(ctx, s.GetCatalogId())
|
||||
if err != nil && errors.IsNotFoundError(err) {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if c == nil {
|
||||
return db.NoRowsAffected, nil
|
||||
}
|
||||
p, err := r.getPersistedDataForCatalog(ctx, c)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
plgClient, ok := r.plugins[plg.GetPublicId()]
|
||||
if !ok || plgClient == nil {
|
||||
return 0, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("plugin %q not available", c.GetPluginId()))
|
||||
}
|
||||
plgHc, err := toPluginCatalog(ctx, c)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
plgHs, err := toPluginSet(ctx, s)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
_, err = plgClient.OnDeleteSet(ctx, &plgpb.OnDeleteSetRequest{Catalog: plgHc, Persisted: p, Set: plgHs})
|
||||
if err != nil {
|
||||
// Even if the plugin returns an error, we ignore it and proceed
|
||||
// with deleting the set.
|
||||
}
|
||||
|
||||
oplogWrapper, err := r.kms.GetWrapper(ctx, scopeId, kms.KeyPurposeOplog)
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg("unable to get oplog wrapper"))
|
||||
}
|
||||
|
||||
var rowsDeleted int
|
||||
_, err = r.writer.DoTx(
|
||||
ctx, db.StdRetryCnt, db.ExpBackoff{},
|
||||
func(_ db.Reader, w db.Writer) (err error) {
|
||||
ds := s.clone()
|
||||
rowsDeleted, err = w.Delete(ctx, ds, db.WithOplog(oplogWrapper, s.oplog(oplog.OpType_OP_TYPE_DELETE)))
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if rowsDeleted > 1 {
|
||||
return errors.New(ctx, errors.MultipleRecords, op, "more than 1 resource would have been deleted")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithMsg(fmt.Sprintf("delete failed for %s", s.PublicId)))
|
||||
}
|
||||
|
||||
return rowsDeleted, nil
|
||||
}
|
||||
|
||||
func (r *Repository) getSets(ctx context.Context, publicId string, catalogId string, opt ...host.Option) ([]*HostSet, *hostplugin.Plugin, error) {
|
||||
const op = "plugin.(Repository).getSets"
|
||||
if publicId == "" && catalogId == "" {
|
||||
|
||||
@@ -2,6 +2,7 @@ package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -654,6 +655,92 @@ func TestRepository_ListSets_Limits(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepository_DeleteSet(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
_, prj := iam.TestScopes(t, iamRepo)
|
||||
plg := hostplg.TestPlugin(t, conn, "create")
|
||||
|
||||
plgm := map[string]plgpb.HostPluginServiceClient{
|
||||
plg.GetPublicId(): NewWrappingPluginClient(TestPluginServer{OnCreateSetFn: func(ctx context.Context, req *plgpb.OnCreateSetRequest) (*plgpb.OnCreateSetResponse, error) {
|
||||
return &plgpb.OnCreateSetResponse{}, nil
|
||||
}}),
|
||||
}
|
||||
c := TestCatalog(t, conn, prj.PublicId, plg.GetPublicId())
|
||||
hostSet := TestSet(t, conn, kms, c, plgm)
|
||||
hostSet2 := TestSet(t, conn, kms, c, plgm)
|
||||
|
||||
newHostSetId, err := newHostSetId(ctx)
|
||||
require.NoError(t, err)
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
pluginChecker func(*plgpb.OnDeleteSetRequest) error
|
||||
want int
|
||||
wantIsErr errors.Code
|
||||
}{
|
||||
{
|
||||
name: "With no public id",
|
||||
pluginChecker: func(req *plgpb.OnDeleteSetRequest) error {
|
||||
assert.Fail(t, "The plugin shouldn't be called")
|
||||
return nil
|
||||
},
|
||||
wantIsErr: errors.InvalidParameter,
|
||||
},
|
||||
{
|
||||
name: "With non existing host set id",
|
||||
in: newHostSetId,
|
||||
pluginChecker: func(req *plgpb.OnDeleteSetRequest) error {
|
||||
assert.Fail(t, "The plugin shouldn't be called")
|
||||
return nil
|
||||
},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "With existing host set id",
|
||||
in: hostSet.PublicId,
|
||||
pluginChecker: func(req *plgpb.OnDeleteSetRequest) error {
|
||||
assert.Equal(t, c.GetPublicId(), req.GetCatalog().GetId())
|
||||
assert.Equal(t, hostSet.GetPublicId(), req.GetSet().GetId())
|
||||
return nil
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "Ignores plugin errors",
|
||||
in: hostSet2.PublicId,
|
||||
pluginChecker: func(req *plgpb.OnDeleteSetRequest) error {
|
||||
assert.Equal(t, c.GetPublicId(), req.GetCatalog().GetId())
|
||||
assert.Equal(t, hostSet2.GetPublicId(), req.GetSet().GetId())
|
||||
return fmt.Errorf("test error")
|
||||
},
|
||||
want: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
repo, err := NewRepository(rw, rw, kms, plgm)
|
||||
assert.NoError(err)
|
||||
require.NotNil(repo)
|
||||
got, err := repo.DeleteSet(ctx, prj.PublicId, tt.in)
|
||||
if tt.wantIsErr != 0 {
|
||||
assert.Truef(errors.Match(errors.T(tt.wantIsErr), err), "want err: %q got: %q", tt.wantIsErr, err)
|
||||
assert.Zero(got)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
assert.EqualValues(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func printoutTable(t *testing.T, rw *db.Db) {
|
||||
ctx := context.Background()
|
||||
hsas := []*hostSetAgg{}
|
||||
|
||||
@@ -123,7 +123,7 @@ func New(ctx context.Context, conf *Config) (*Controller, error) {
|
||||
external_host_plugins.WithHostPluginExecutionDir(conf.RawConfig.Plugins.ExecutionDir),
|
||||
external_host_plugins.WithLogger(hclog.NewNullLogger()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating azure host plugin")
|
||||
return nil, fmt.Errorf("error creating azure host plugin: %w", err)
|
||||
}
|
||||
conf.ShutdownFuncs = append(conf.ShutdownFuncs, azureCleanup)
|
||||
if _, err := conf.RegisterHostPlugin(ctx, "azure", azureSvcClient, hostplugin.WithDescription("Built-in Azure host plugin")); err != nil {
|
||||
|
||||
@@ -534,13 +534,26 @@ func (s Service) updateInRepo(ctx context.Context, projId, id string, mask []str
|
||||
|
||||
func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) {
|
||||
const op = "host_catalogs.(Service).deleteFromRepo"
|
||||
repo, err := s.staticRepoFn()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
rows, err := repo.DeleteCatalog(ctx, id)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete host"))
|
||||
rows := 0
|
||||
switch host.SubtypeFromId(id) {
|
||||
case static.Subtype:
|
||||
repo, err := s.staticRepoFn()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
rows, err = repo.DeleteCatalog(ctx, id)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete host"))
|
||||
}
|
||||
case plugin.Subtype:
|
||||
repo, err := s.pluginHostRepoFn()
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
rows, err = repo.DeleteCatalog(ctx, id)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete host"))
|
||||
}
|
||||
}
|
||||
return rows > 0, nil
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
func TestDelete_Static(t *testing.T) {
|
||||
t.Parallel()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
@@ -524,6 +524,76 @@ func TestDelete(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete_Plugin(t *testing.T) {
|
||||
t.Parallel()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
_, proj := iam.TestScopes(t, iamRepo)
|
||||
rw := db.New(conn)
|
||||
repo := func() (*static.Repository, error) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginHostRepo := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceClient{})
|
||||
}
|
||||
pluginRepo := func() (*host.Repository, error) {
|
||||
return host.NewRepository(rw, rw, kms)
|
||||
}
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
plg := host.TestPlugin(t, conn, "test")
|
||||
hc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
|
||||
s, err := host_catalogs.NewService(repo, pluginHostRepo, pluginRepo, iamRepoFn)
|
||||
require.NoError(t, err, "Couldn't create a new host catalog service.")
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
scopeId string
|
||||
req *pbs.DeleteHostCatalogRequest
|
||||
res *pbs.DeleteHostCatalogResponse
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Delete an Existing HostCatalog",
|
||||
scopeId: proj.GetPublicId(),
|
||||
req: &pbs.DeleteHostCatalogRequest{
|
||||
Id: hc.GetPublicId(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Delete bad id HostCatalog",
|
||||
scopeId: proj.GetPublicId(),
|
||||
req: &pbs.DeleteHostCatalogRequest{
|
||||
Id: plugin.HostCatalogPrefix + "_doesntexis",
|
||||
},
|
||||
err: handlers.ApiErrorWithCode(codes.NotFound),
|
||||
},
|
||||
{
|
||||
name: "Bad HostCatalog Id formatting",
|
||||
scopeId: proj.GetPublicId(),
|
||||
req: &pbs.DeleteHostCatalogRequest{
|
||||
Id: plugin.HostCatalogPrefix + "_bad_format",
|
||||
},
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
got, gErr := s.DeleteHostCatalog(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), tc.req)
|
||||
if tc.err != nil {
|
||||
require.Error(gErr)
|
||||
assert.True(errors.Is(gErr, tc.err), "DeleteHostCatalog(%+v) got error %v, wanted %v", tc.req, gErr, tc.err)
|
||||
}
|
||||
assert.EqualValuesf(tc.res, got, "DeleteHostCatalog(%q) got response %q, wanted %q", tc.req, got, tc.res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete_twice(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
@@ -525,13 +525,26 @@ func (s Service) updateInRepo(ctx context.Context, scopeId, catalogId string, re
|
||||
|
||||
func (s Service) deleteFromRepo(ctx context.Context, scopeId, id string) (bool, error) {
|
||||
const op = "host_sets.(Service).deleteFromRepo"
|
||||
repo, err := s.staticRepoFn()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
rows, err := repo.DeleteSet(ctx, scopeId, id)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete host"))
|
||||
rows := 0
|
||||
switch host.SubtypeFromId(id) {
|
||||
case static.Subtype:
|
||||
repo, err := s.staticRepoFn()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
rows, err = repo.DeleteSet(ctx, scopeId, id)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete host"))
|
||||
}
|
||||
case plugin.Subtype:
|
||||
repo, err := s.pluginRepoFn()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
rows, err = repo.DeleteSet(ctx, scopeId, id)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete host"))
|
||||
}
|
||||
}
|
||||
return rows > 0, nil
|
||||
}
|
||||
@@ -900,7 +913,7 @@ func validateUpdateRequest(ctx context.Context, req *pbs.UpdateHostSetRequest) e
|
||||
}
|
||||
|
||||
func validateDeleteRequest(req *pbs.DeleteHostSetRequest) error {
|
||||
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, static.HostSetPrefix)
|
||||
return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, static.HostSetPrefix, plugin.HostSetPrefix)
|
||||
}
|
||||
|
||||
func validateListRequest(req *pbs.ListHostSetsRequest) error {
|
||||
|
||||
@@ -445,7 +445,7 @@ func TestList_Plugin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
func TestDelete_Static(t *testing.T) {
|
||||
t.Parallel()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
@@ -494,18 +494,86 @@ func TestDelete(t *testing.T) {
|
||||
err: handlers.ApiErrorWithCode(codes.NotFound),
|
||||
},
|
||||
{
|
||||
name: "Delete bad host catalog id in Host Set",
|
||||
name: "Bad Host Id formatting",
|
||||
scopeId: proj.GetPublicId(),
|
||||
req: &pbs.DeleteHostSetRequest{
|
||||
Id: static.HostSetPrefix + "_bad_format",
|
||||
},
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
got, gErr := s.DeleteHostSet(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), tc.req)
|
||||
if tc.err != nil {
|
||||
require.Error(gErr)
|
||||
assert.True(errors.Is(gErr, tc.err), "DeleteHostSet(%+v) got error %v, wanted %v", tc.req, gErr, tc.err)
|
||||
}
|
||||
assert.Empty(cmp.Diff(tc.res, got, protocmp.Transform()), "DeleteHostSet(%q) got response %q, wanted %q", tc.req, got, tc.res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete_Plugin(t *testing.T) {
|
||||
t.Parallel()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
kms := kms.TestKms(t, conn, wrapper)
|
||||
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iamRepo, nil
|
||||
}
|
||||
|
||||
_, proj := iam.TestScopes(t, iamRepo)
|
||||
|
||||
rw := db.New(conn)
|
||||
repoFn := func() (*static.Repository, error) {
|
||||
return static.NewRepository(rw, rw, kms)
|
||||
}
|
||||
pluginRepoFn := func() (*plugin.Repository, error) {
|
||||
return plugin.NewRepository(rw, rw, kms, map[string]plgpb.HostPluginServiceClient{})
|
||||
}
|
||||
name := "test"
|
||||
plg := hostplugin.TestPlugin(t, conn, name)
|
||||
plgm := map[string]plgpb.HostPluginServiceClient{
|
||||
plg.GetPublicId(): plugin.NewWrappingPluginClient(&plugin.TestPluginServer{}),
|
||||
}
|
||||
|
||||
hc := plugin.TestCatalog(t, conn, proj.GetPublicId(), plg.GetPublicId())
|
||||
h := plugin.TestSet(t, conn, kms, hc, plgm)
|
||||
|
||||
s, err := host_sets.NewService(repoFn, pluginRepoFn)
|
||||
require.NoError(t, err, "Couldn't create a new host set service.")
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
scopeId string
|
||||
req *pbs.DeleteHostSetRequest
|
||||
res *pbs.DeleteHostSetResponse
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Delete an Existing Host Set",
|
||||
scopeId: proj.GetPublicId(),
|
||||
req: &pbs.DeleteHostSetRequest{
|
||||
Id: h.GetPublicId(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Delete bad id Host Set",
|
||||
scopeId: proj.GetPublicId(),
|
||||
req: &pbs.DeleteHostSetRequest{
|
||||
Id: plugin.HostSetPrefix + "_doesntexis",
|
||||
},
|
||||
err: handlers.ApiErrorWithCode(codes.NotFound),
|
||||
},
|
||||
{
|
||||
name: "Bad Host Id formatting",
|
||||
scopeId: proj.GetPublicId(),
|
||||
req: &pbs.DeleteHostSetRequest{
|
||||
Id: static.HostSetPrefix + "_bad_format",
|
||||
Id: plugin.HostSetPrefix + "_bad_format",
|
||||
},
|
||||
err: handlers.ApiErrorWithCode(codes.InvalidArgument),
|
||||
},
|
||||
|
||||
@@ -117,6 +117,23 @@ func TestCrud(t *testing.T) {
|
||||
apiErr := api.AsServerError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(http.StatusNotFound, apiErr.Response().StatusCode())
|
||||
|
||||
// Plugin catalogs
|
||||
c, err := hcClient.Create(tc.Context(), "plugin", proj.GetPublicId(), hostcatalogs.WithName("pluginfoo"), hostcatalogs.WithPluginId("pl_1234567890"),
|
||||
hostcatalogs.WithAttributes(map[string]interface{}{"foo": "bar"}))
|
||||
require.NoError(err)
|
||||
|
||||
c, err = hcClient.Read(tc.Context(), c.Item.Id)
|
||||
assert.NoError(err)
|
||||
|
||||
_, err = hcClient.Delete(tc.Context(), c.Item.Id)
|
||||
assert.NoError(err)
|
||||
|
||||
_, err = hcClient.Delete(tc.Context(), c.Item.Id)
|
||||
require.Error(err)
|
||||
apiErr = api.AsServerError(err)
|
||||
assert.NotNil(apiErr)
|
||||
assert.EqualValues(http.StatusNotFound, apiErr.Response().StatusCode())
|
||||
}
|
||||
|
||||
func TestErrors(t *testing.T) {
|
||||
|
||||
@@ -127,7 +127,8 @@ func TestCrud(t *testing.T) {
|
||||
client.SetToken(token.Token)
|
||||
_, proj := iam.TestScopes(t, tc.IamRepo(), iam.WithUserId(token.UserId))
|
||||
|
||||
hc, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId())
|
||||
hcClient := hostcatalogs.NewClient(client)
|
||||
hc, err := hcClient.Create(tc.Context(), "static", proj.GetPublicId())
|
||||
require.NoError(err)
|
||||
require.NotNil(hc)
|
||||
|
||||
@@ -164,6 +165,25 @@ func TestCrud(t *testing.T) {
|
||||
apiErr := api.AsServerError(err)
|
||||
require.NotNil(apiErr)
|
||||
assert.EqualValues(http.StatusNotFound, apiErr.Response().StatusCode())
|
||||
|
||||
// Plugin Sets
|
||||
c, err := hcClient.Create(tc.Context(), "plugin", proj.GetPublicId(), hostcatalogs.WithName("pluginfoo"), hostcatalogs.WithPluginId("pl_1234567890"),
|
||||
hostcatalogs.WithAttributes(map[string]interface{}{"foo": "bar"}))
|
||||
require.NoError(err)
|
||||
|
||||
h, err = hClient.Create(tc.Context(), c.Item.Id, hostsets.WithName("foo"))
|
||||
checkHost(t, "create", h.Item, err, "foo", 1)
|
||||
|
||||
h, err = hClient.Read(tc.Context(), h.Item.Id)
|
||||
checkHost(t, "read", h.Item, err, "foo", 1)
|
||||
|
||||
_, err = hClient.Delete(tc.Context(), h.Item.Id)
|
||||
assert.NoError(err)
|
||||
_, err = hClient.Delete(tc.Context(), h.Item.Id)
|
||||
require.Error(err)
|
||||
apiErr = api.AsServerError(err)
|
||||
require.NotNil(apiErr)
|
||||
assert.EqualValues(http.StatusNotFound, apiErr.Response().StatusCode())
|
||||
}
|
||||
|
||||
// TODO: Get better coverage for expected errors and error formats.
|
||||
|
||||
Reference in new issue
Block a user