diff --git a/internal/db/model.go b/internal/db/model.go index 63d06ec9c..79d58ed30 100644 --- a/internal/db/model.go +++ b/internal/db/model.go @@ -166,6 +166,25 @@ func (d *Database) ForEachModel(ctx context.Context, f func(m *dbmodel.Model) er return nil } +func (d *Database) FetchModelsByUUID(ctx context.Context, modelUUIDs []string) ([]dbmodel.Model, error) { + const op = errors.Op("db.ForEachModel") + + if err := d.ready(); err != nil { + return nil, errors.E(op, err) + } + var models []dbmodel.Model + db := d.DB.WithContext(ctx) + err := db.Where("uuid IN ?", modelUUIDs).Find(&models).Error + if err != nil { + err = dbError(err) + if errors.ErrorCode(err) == errors.CodeNotFound { + return nil, errors.E(op, err, "model not found") + } + return nil, errors.E(op, dbError(err)) + } + return models, nil +} + func preloadModel(prefix string, db *gorm.DB) *gorm.DB { if len(prefix) > 0 && prefix[len(prefix)-1] != '.' { prefix += "." diff --git a/internal/db/model_test.go b/internal/db/model_test.go index 3ba011106..07b3cee01 100644 --- a/internal/db/model_test.go +++ b/internal/db/model_test.go @@ -5,6 +5,7 @@ package db_test import ( "context" "database/sql" + "sort" "testing" qt "github.com/frankban/quicktest" @@ -718,3 +719,85 @@ func (s *dbSuite) TestForEachModel(c *qt.C) { "00000002-0000-0000-0000-000000000003", }) } + +const testFetchModelsByUUIDEnv = `clouds: +- name: test + type: test + regions: + - name: test-region +cloud-credentials: +- name: test-cred + cloud: test + owner: alice@external + type: empty +controllers: +- name: test + uuid: 00000001-0000-0000-0000-000000000001 + cloud: test + region: test-region +models: +- name: test-1 + uuid: 00000002-0000-0000-0000-000000000001 + owner: alice@external + cloud: test + region: test-region + cloud-credential: test-cred + controller: test + users: + - user: alice@external + access: admin + - user: bob@external + access: write +- name: test-2 + uuid: 00000002-0000-0000-0000-000000000002 + owner: bob@external + cloud: test + region: test-region + cloud-credential: test-cred + controller: test + users: + - user: bob@external + access: admin +- name: test-3 + uuid: 00000002-0000-0000-0000-000000000003 + owner: bob@external + cloud: test + region: test-region + cloud-credential: test-cred + controller: test + users: + - user: bob@external + access: admin +` + +func TestFetchModelsByUUIDlUnconfiguredDatabase(t *testing.T) { + c := qt.New(t) + + var d db.Database + _, err := d.FetchModelsByUUID(context.Background(), nil) + c.Check(err, qt.ErrorMatches, `database not configured`) + c.Check(errors.ErrorCode(err), qt.Equals, errors.CodeServerConfiguration) +} + +func (s *dbSuite) TestFetchModelsByUUID(c *qt.C) { + ctx := context.Background() + err := s.Database.Migrate(context.Background(), true) + c.Assert(err, qt.Equals, nil) + + env := jimmtest.ParseEnvironment(c, testFetchModelsByUUIDEnv) + env.PopulateDB(c, *s.Database, nil) + + modelUUIDs := []string{ + "00000002-0000-0000-0000-000000000001", + "00000002-0000-0000-0000-000000000002", + "00000002-0000-0000-0000-000000000003", + } + models, err := s.Database.FetchModelsByUUID(ctx, modelUUIDs) + c.Assert(err, qt.IsNil) + sort.Slice(models, func(i, j int) bool { + return models[i].UUID.String < models[j].UUID.String + }) + c.Check(models[0].UUID.String, qt.Equals, "00000002-0000-0000-0000-000000000001") + c.Check(models[1].UUID.String, qt.Equals, "00000002-0000-0000-0000-000000000002") + c.Check(models[2].UUID.String, qt.Equals, "00000002-0000-0000-0000-000000000003") +} diff --git a/internal/jujuapi/jimm.go b/internal/jujuapi/jimm.go index 061682304..e87274e7d 100644 --- a/internal/jujuapi/jimm.go +++ b/internal/jujuapi/jimm.go @@ -497,14 +497,15 @@ func (r *controllerRoot) RemoveCloudFromController(ctx context.Context, req apip func (r *controllerRoot) CrossModelQuery(ctx context.Context, req apiparams.CrossModelQueryRequest) (apiparams.CrossModelQueryResponse, error) { const op = errors.Op("jujuapi.CrossModelQuery") - usersModels, err := r.jimm.Database.GetUserModels(ctx, r.user.User) + modelUUIDs, err := r.user.ListModels(ctx) if err != nil { - return apiparams.CrossModelQueryResponse{}, errors.E(op, errors.Code("failed to get models for user")) + return apiparams.CrossModelQueryResponse{}, errors.E(op, errors.Code("failed to list user's model access")) } - models := make([]dbmodel.Model, len(usersModels)) - for i, m := range usersModels { - models[i] = m.Model_ + models, err := r.jimm.Database.FetchModelsByUUID(ctx, modelUUIDs) + if err != nil { + return apiparams.CrossModelQueryResponse{}, errors.E(op, errors.Code("failed to get models for user")) } + switch strings.TrimSpace(strings.ToLower(req.Type)) { case "jq": return r.jimm.QueryModelsJq(ctx, models, req.Query)