Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into athena-connector
Browse files Browse the repository at this point in the history
  • Loading branch information
Egor Ryashin committed Sep 13, 2023
2 parents f0bbee9 + 0d53847 commit 8d4b69b
Show file tree
Hide file tree
Showing 174 changed files with 15,526 additions and 8,835 deletions.
2 changes: 2 additions & 0 deletions admin/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ type DB interface {
FindBookmark(ctx context.Context, bookmarkID string) (*Bookmark, error)
InsertBookmark(ctx context.Context, opts *InsertBookmarkOptions) (*Bookmark, error)
DeleteBookmark(ctx context.Context, bookmarkID string) error

SearchProjectUsers(ctx context.Context, projectID, emailQuery string, afterEmail string, limit int) ([]*User, error)
}

// Tx represents a database transaction. It can only be used to commit and rollback transactions.
Expand Down
19 changes: 19 additions & 0 deletions admin/database/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,25 @@ func (c *connection) FindUsersByEmailPattern(ctx context.Context, emailPattern,
return res, nil
}

// SearchProjectUsers searches for users that have access to the project.
func (c *connection) SearchProjectUsers(ctx context.Context, projectID, emailQuery, afterEmail string, limit int) ([]*database.User, error) {
var res []*database.User
err := c.getDB(ctx).SelectContext(ctx, &res, `
SELECT u.* FROM users u
WHERE u.id IN (
SELECT upr.user_id FROM users_projects_roles upr WHERE upr.project_id=$1
UNION
SELECT ugu.user_id FROM usergroups_projects_roles ugpr JOIN usergroups_users ugu ON ugpr.usergroup_id = ugu.usergroup_id WHERE ugpr.project_id=$1
)
AND lower(u.email) LIKE lower($2)
AND lower(u.email) > lower($3)
ORDER BY lower(u.email) ASC LIMIT $4`, projectID, emailQuery, afterEmail, limit)
if err != nil {
return nil, parseErr("users", err)
}
return res, nil
}

func (c *connection) InsertUser(ctx context.Context, opts *database.InsertUserOptions) (*database.User, error) {
if err := database.Validate(opts); err != nil {
return nil, err
Expand Down
30 changes: 25 additions & 5 deletions admin/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"path"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -57,21 +58,40 @@ func (s *Service) createDeployment(ctx context.Context, opts *createDeploymentOp
// Build instance config
instanceID := strings.ReplaceAll(uuid.New().String(), "-", "")
olapDriver := opts.ProdOLAPDriver
olapDSN := opts.ProdOLAPDSN
olapConfig := map[string]string{}
var embedCatalog bool
var ingestionLimit int64
if olapDriver == "duckdb" {
if olapDSN != "" {
switch olapDriver {
case "duckdb":
if opts.ProdOLAPDSN != "" {
return nil, fmt.Errorf("passing a DSN is not allowed for driver 'duckdb'")
}
if opts.ProdSlots == 0 {
return nil, fmt.Errorf("slot count can't be 0 for driver 'duckdb'")
}

olapConfig["dsn"] = fmt.Sprintf("%s.db?max_memory=%dGB", path.Join(alloc.DataDir, instanceID), alloc.MemoryGB)
olapConfig["pool_size"] = strconv.Itoa(alloc.CPU)
embedCatalog = true
ingestionLimit = alloc.StorageBytes
case "duckdb-vip":
if opts.ProdOLAPDSN != "" {
return nil, fmt.Errorf("passing a DSN is not allowed for driver 'duckdb-vip'")
}
if opts.ProdSlots == 0 {
return nil, fmt.Errorf("slot count can't be 0 for driver 'duckdb-vip'")
}

olapDSN = fmt.Sprintf("%s.db?rill_pool_size=%d&max_memory=%dGB", path.Join(alloc.DataDir, instanceID), alloc.CPU, alloc.MemoryGB)
// NOTE: Rewriting to a "duckdb" driver without CPU, memory, or storage limits
olapDriver = "duckdb"
olapConfig["dsn"] = fmt.Sprintf("%s.db", path.Join(alloc.DataDir, instanceID))
olapConfig["pool_size"] = "8"
embedCatalog = true
ingestionLimit = 0
default:
olapConfig["dsn"] = opts.ProdOLAPDSN
embedCatalog = false
ingestionLimit = 0
}

// Open a runtime client
Expand All @@ -94,7 +114,7 @@ func (s *Service) createDeployment(ctx context.Context, opts *createDeploymentOp
{
Name: "olap",
Type: olapDriver,
Config: map[string]string{"dsn": olapDSN},
Config: olapConfig,
},
{
Name: "repo",
Expand Down
126 changes: 126 additions & 0 deletions admin/permissions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package admin

import (
"context"

"github.com/rilldata/rill/admin/database"
adminv1 "github.com/rilldata/rill/proto/gen/rill/admin/v1"
)

// OrganizationPermissionsForUser resolves organization permissions for a user.
func (s *Service) OrganizationPermissionsForUser(ctx context.Context, orgID, userID string) (*adminv1.OrganizationPermissions, error) {
roles, err := s.DB.ResolveOrganizationRolesForUser(ctx, userID, orgID)
if err != nil {
return nil, err
}

composite := &adminv1.OrganizationPermissions{}
for _, role := range roles {
composite = unionOrgRoles(composite, role)
}

return composite, nil
}

// OrganizationPermissionsForService resolves organization permissions for a service.
// A service currently gets full permissions on the org they belong to.
func (s *Service) OrganizationPermissionsForService(ctx context.Context, orgID, serviceID string) (*adminv1.OrganizationPermissions, error) {
service, err := s.DB.FindService(ctx, serviceID)
if err != nil {
return nil, err
}

// Services get full permissions on the org they belong to
if orgID == service.OrgID {
return &adminv1.OrganizationPermissions{
ReadOrg: true,
ManageOrg: true,
ReadProjects: true,
CreateProjects: true,
ManageProjects: true,
ReadOrgMembers: true,
ManageOrgMembers: true,
}, nil
}

return &adminv1.OrganizationPermissions{}, nil
}

// ProjectPermissionsForUser resolves project permissions for a user.
func (s *Service) ProjectPermissionsForUser(ctx context.Context, projectID, userID string, orgPerms *adminv1.OrganizationPermissions) (*adminv1.ProjectPermissions, error) {
// ManageProjects permission on the org gives full access to all projects in the org (only org admins have this)
if orgPerms.ManageProjects {
return &adminv1.ProjectPermissions{
ReadProject: true,
ManageProject: true,
ReadProd: true,
ReadProdStatus: true,
ManageProd: true,
ReadDev: true,
ReadDevStatus: true,
ManageDev: true,
ReadProjectMembers: true,
ManageProjectMembers: true,
}, nil
}

roles, err := s.DB.ResolveProjectRolesForUser(ctx, userID, projectID)
if err != nil {
return nil, err
}

composite := &adminv1.ProjectPermissions{}
for _, role := range roles {
composite = unionProjectRoles(composite, role)
}

return composite, nil
}

// ProjectPermissionsService resolves project permissions for a service.
// A service currently gets full permissions on all projects in the org they belong to.
func (s *Service) ProjectPermissionsForService(ctx context.Context, projectID, serviceID string, orgPerms *adminv1.OrganizationPermissions) (*adminv1.ProjectPermissions, error) {
if orgPerms.ManageProjects {
return &adminv1.ProjectPermissions{
ReadProject: true,
ManageProject: true,
ReadProd: true,
ReadProdStatus: true,
ManageProd: true,
ReadDev: true,
ReadDevStatus: true,
ManageDev: true,
ReadProjectMembers: true,
ManageProjectMembers: true,
}, nil
}

return &adminv1.ProjectPermissions{}, nil
}

func unionOrgRoles(a *adminv1.OrganizationPermissions, b *database.OrganizationRole) *adminv1.OrganizationPermissions {
return &adminv1.OrganizationPermissions{
ReadOrg: a.ReadOrg || b.ReadOrg,
ManageOrg: a.ManageOrg || b.ManageOrg,
ReadProjects: a.ReadProjects || b.ReadProjects,
CreateProjects: a.CreateProjects || b.CreateProjects,
ManageProjects: a.ManageProjects || b.ManageProjects,
ReadOrgMembers: a.ReadOrgMembers || b.ReadOrgMembers,
ManageOrgMembers: a.ManageOrgMembers || b.ManageOrgMembers,
}
}

func unionProjectRoles(a *adminv1.ProjectPermissions, b *database.ProjectRole) *adminv1.ProjectPermissions {
return &adminv1.ProjectPermissions{
ReadProject: a.ReadProject || b.ReadProject,
ManageProject: a.ManageProject || b.ManageProject,
ReadProd: a.ReadProd || b.ReadProd,
ReadProdStatus: a.ReadProdStatus || b.ReadProdStatus,
ManageProd: a.ManageProd || b.ManageProd,
ReadDev: a.ReadDev || b.ReadDev,
ReadDevStatus: a.ReadDevStatus || b.ReadDevStatus,
ManageDev: a.ManageDev || b.ManageDev,
ReadProjectMembers: a.ReadProjectMembers || b.ReadProjectMembers,
ManageProjectMembers: a.ManageProjectMembers || b.ManageProjectMembers,
}
}
2 changes: 1 addition & 1 deletion admin/provisioner/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,6 @@ func (p *StaticProvisioner) Provision(ctx context.Context, opts *ProvisionOption
DataDir: target.DataDir,
CPU: 1 * opts.Slots,
MemoryGB: 2 * opts.Slots,
StorageBytes: int64(opts.Slots) * 10 * int64(datasize.GB),
StorageBytes: int64(opts.Slots) * 40 * int64(datasize.GB),
}, nil
}
6 changes: 3 additions & 3 deletions admin/provisioner/provisioner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ func Test_staticProvisioner_Provision(t *testing.T) {
name: "all applicable ",
spec: spec,
opts: &ProvisionOptions{OLAPDriver: "duckdb", Slots: 1, Region: "us-east-1"},
want: &Allocation{CPU: 1, MemoryGB: 2, StorageBytes: int64(10) * int64(datasize.GB)},
want: &Allocation{CPU: 1, MemoryGB: 2, StorageBytes: int64(40) * int64(datasize.GB)},
wantErr: false,
},
{
name: "one applicable ",
spec: spec,
opts: &ProvisionOptions{OLAPDriver: "duckdb", Slots: 4, Region: "us-east-1"},
want: &Allocation{CPU: 4, MemoryGB: 8, StorageBytes: int64(40) * int64(datasize.GB), Host: "host_1"},
want: &Allocation{CPU: 4, MemoryGB: 8, StorageBytes: int64(160) * int64(datasize.GB), Host: "host_1"},
wantErr: false,
},
{
Expand All @@ -120,7 +120,7 @@ func Test_staticProvisioner_Provision(t *testing.T) {
},
},
opts: &ProvisionOptions{OLAPDriver: "duckdb", Slots: 1, Region: "us-east-2"},
want: &Allocation{CPU: 1, MemoryGB: 2, StorageBytes: int64(10) * int64(datasize.GB), Host: "host_2"},
want: &Allocation{CPU: 1, MemoryGB: 2, StorageBytes: int64(40) * int64(datasize.GB), Host: "host_2"},
wantErr: false,
},
}
Expand Down
Loading

0 comments on commit 8d4b69b

Please sign in to comment.