Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
43 changes: 43 additions & 0 deletions apis/cmk/cmk-ui.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,30 @@ paths:
$ref: "#/components/responses/429"
"500":
$ref: "#/components/responses/500"
/systems/filterOptions:
get:
tags:
- Systems
summary: Get System Filter Values
description: Get system possible values for filters
operationId: getFilters
responses:
"200":
description: System retrieved
content:
application/json:
schema:
$ref: "#/components/schemas/SystemFilters"
"400":
$ref: "#/components/responses/400"
"403":
$ref: "#/components/responses/403"
"404":
$ref: "#/components/responses/404"
"429":
$ref: "#/components/responses/429"
"500":
$ref: "#/components/responses/500"
/systems/{systemID}:
get:
tags:
Expand Down Expand Up @@ -1507,6 +1531,25 @@ components:
enum:
- RETRY
- CANCEL
SystemFilters:
description: System Filters
type: object
properties:
region:
type: array
items:
type: string
description: List of existing system regions
type:
type: array
items:
type: string
description: List of existing system types
keyConfigurationName:
type: array
items:
type: string
description: List of existing system key configurations
ClientCertificates:
type: object
properties:
Expand Down
301 changes: 210 additions & 91 deletions internal/api/cmkapi/cmkapi.go

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions internal/authz/api_endpoint_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ var allRestrictions = []Restricted{
APIResourceTypeName: APIResourceTypeSystem,
APIAction: APIActionRead,
},
{
APIPath: "/systems/filterOptions",
APIMethod: APIMethodGet,
APIResourceTypeName: APIResourceTypeSystem,
APIAction: APIActionRead,
},
{
APIPath: "/systems/{systemID}",
APIMethod: APIMethodGet,
Expand Down
33 changes: 26 additions & 7 deletions internal/authz/repo/authz_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import (
cmkcontext "github.com/openkcm/cmk/utils/context"
)

var (
ErrUnauthorized = errors.New("action on resource unauthorized")
)
var ErrUnauthorized = errors.New("action on resource unauthorized")

type AuthzRepo struct {
repo repo.Repo
Expand All @@ -21,15 +19,17 @@ type AuthzRepo struct {

func NewAuthzRepo(
repo repo.Repo, authzLoader *authz_loader.AuthzLoader[authz.RepoResourceTypeName,
authz.RepoAction]) *AuthzRepo {
authz.RepoAction],
) *AuthzRepo {
return &AuthzRepo{
repo: repo,
authzLoader: authzLoader,
}
}

func (r *AuthzRepo) Create(
ctx context.Context, resource repo.Resource) error {
ctx context.Context, resource repo.Resource,
) error {
err := r.checkResourceAuthZ(ctx, resource, authz.RepoActionCreate)
if err != nil {
return err
Expand Down Expand Up @@ -136,8 +136,26 @@ func (r *AuthzRepo) Transaction(ctx context.Context, txFunc repo.TransactionFunc
return r.repo.Transaction(ctx, txFunc)
}

func (r *AuthzRepo) GetFilterOptions(
ctx context.Context,
resource repo.Resource,
columns []repo.Filter,
query repo.Query,
) error {
err := r.checkResourceAuthZ(ctx, resource, authz.RepoActionList)
if err != nil {
return err
}
err = r.checkQueryAuthZ(ctx, query, authz.RepoActionList)
if err != nil {
return err
}
return r.repo.GetFilterOptions(ctx, resource, columns, query)
}

func (r *AuthzRepo) checkResourceAuthZ(
ctx context.Context, resource repo.Resource, action authz.RepoAction) error {
ctx context.Context, resource repo.Resource, action authz.RepoAction,
) error {
tenantID, err := cmkcontext.ExtractTenantID(ctx)
if err != nil {
return err
Expand All @@ -159,7 +177,8 @@ func (r *AuthzRepo) checkResourceAuthZ(
}

func (r *AuthzRepo) checkQueryAuthZ(
ctx context.Context, query repo.Query, action authz.RepoAction) error {
ctx context.Context, query repo.Query, action authz.RepoAction,
) error {
tenantID, err := cmkcontext.ExtractTenantID(ctx)
if err != nil {
return err
Expand Down
12 changes: 12 additions & 0 deletions internal/controllers/cmk/system_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,15 @@ func (c *APIController) UnlinkSystemAction(

return cmkapi.UnlinkSystemAction204Response(struct{}{}), nil
}

func (c *APIController) GetFilters(
ctx context.Context,
_ cmkapi.GetFiltersRequestObject,
) (cmkapi.GetFiltersResponseObject, error) {
filters, err := c.Manager.System.GetFilters(ctx)
if err != nil {
return nil, err
}

return cmkapi.GetFilters200JSONResponse(filters), nil
}
Comment thread
jmpTeixeira02 marked this conversation as resolved.
41 changes: 41 additions & 0 deletions internal/controllers/cmk/system_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -961,3 +961,44 @@ func TestUnlinkSystemAction(t *testing.T) {
})
}
}

func TestGetFilters(t *testing.T) {
db, sv, tenant := startAPISystems(t, testutils.TestAPIServerConfig{})
ctx := cmkcontext.CreateTenantContext(t.Context(), tenant)
r := sql.NewRepository(db)

authClient := testutils.NewAuthClient(ctx, t, r, testutils.WithKeyAdminRole())

keyConfig1 := testutils.NewKeyConfig(func(k *model.KeyConfiguration) {
k.Name = "kcName1"
}, testutils.WithAuthClientDataKC(authClient))
keyConfig2 := testutils.NewKeyConfig(func(k *model.KeyConfiguration) {
k.Name = "kcName2"
}, testutils.WithAuthClientDataKC(authClient))

system1 := testutils.NewSystem(func(s *model.System) {
s.Type = "type1"
s.Region = "region1"
s.KeyConfigurationID = &keyConfig1.ID
})

system2 := testutils.NewSystem(func(s *model.System) {
s.Type = "type2"
s.Region = "region2"
s.KeyConfigurationID = &keyConfig2.ID
})

testutils.CreateTestEntities(ctx, t, r, keyConfig1, keyConfig2, system1, system2)

w := testutils.MakeHTTPRequest(t, sv, testutils.RequestOptions{
Method: http.MethodGet,
Endpoint: "/systems/filterOptions",
Tenant: tenant,
AdditionalContext: authClient.GetClientMap(),
})

assert.Equal(t, http.StatusOK, w.Code)

response := testutils.GetJSONBody[cmkapi.SystemFilters](t, w)
assert.NotNil(t, response)
}
Comment thread
jmpTeixeira02 marked this conversation as resolved.
27 changes: 27 additions & 0 deletions internal/manager/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package manager

import (
"context"
"fmt"
"log/slog"
"strings"

Expand Down Expand Up @@ -43,6 +44,7 @@ type System interface {
systemID uuid.UUID,
action cmkapi.SystemRecoveryActionBodyAction,
) error
GetFilters(ctx context.Context) (cmkapi.SystemFilters, error)
}

type SystemManager struct {
Expand Down Expand Up @@ -429,6 +431,31 @@ func (m *SystemManager) UnlinkSystemAction(ctx context.Context, systemID uuid.UU
return nil
}

func (m *SystemManager) GetFilters(ctx context.Context) (cmkapi.SystemFilters, error) {
var types []string
var regions []string
var keyConfigNames []string

query := repo.NewQuery().Join(repo.LeftJoin, repo.JoinCondition{
JoinTable: &model.KeyConfiguration{},
JoinField: repo.IDField,
Table: &model.System{},
Field: repo.KeyConfigIDField,
})
filters := []repo.Filter{
{Values: &types, Column: repo.TypeField},
{Values: &regions, Column: repo.RegionField},
{Values: &keyConfigNames, Column: fmt.Sprintf("%s.%s", model.KeyConfiguration{}.TableName(), repo.NameField)},
}
err := m.repo.GetFilterOptions(ctx, model.System{}, filters, *query)
Comment thread
jmpTeixeira02 marked this conversation as resolved.
Outdated

return cmkapi.SystemFilters{
KeyConfigurationName: &keyConfigNames,
Region: &regions,
Type: &types,
}, err
}

func (m *SystemManager) UnmapSystemFromRegistry(ctx context.Context, system *model.System) error {
tenant, err := cmkcontext.ExtractTenantID(ctx)
if err != nil {
Expand Down
44 changes: 44 additions & 0 deletions internal/manager/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1508,3 +1508,47 @@ func TestRefreshSystems(t *testing.T) {
},
)
}

func TestGetFilters(t *testing.T) {
m, db, tenant := SetupSystemManager(t, nil)
ctx := testutils.CreateCtxWithTenant(tenant)
r := sql.NewRepository(db)

keyConfig1 := testutils.NewKeyConfig(func(k *model.KeyConfiguration) {
k.Name = "kcName1"
})
keyConfig2 := testutils.NewKeyConfig(func(k *model.KeyConfiguration) {
k.Name = "kcName2"
})

system1 := testutils.NewSystem(func(s *model.System) {
s.Type = "type1"
s.Region = "region1"
s.KeyConfigurationID = &keyConfig1.ID
})

system2 := testutils.NewSystem(func(s *model.System) {
s.Type = "type2"
s.Region = "region2"
s.KeyConfigurationID = &keyConfig2.ID
})

testutils.CreateTestEntities(ctx, t, r, keyConfig1, keyConfig2, system1, system2)

t.Run("Should get filters for system", func(t *testing.T) {
filters, err := m.GetFilters(ctx)
assert.NoError(t, err)

assert.Len(t, *filters.Type, 2)
assert.Contains(t, *filters.Type, system1.Type)
assert.Contains(t, *filters.Type, system2.Type)

assert.Len(t, *filters.Region, 2)
assert.Contains(t, *filters.Region, system1.Region)
assert.Contains(t, *filters.Region, system2.Region)

assert.Len(t, *filters.KeyConfigurationName, 2)
assert.Contains(t, *filters.KeyConfigurationName, keyConfig1.Name)
assert.Contains(t, *filters.KeyConfigurationName, keyConfig2.Name)
})
}
7 changes: 7 additions & 0 deletions internal/manager/tenant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ func (s *mockSystemManager) UnlinkSystemAction(context.Context, uuid.UUID, strin
func (s *mockSystemManager) GetAllSystems(context.Context, repo.QueryMapper) ([]*model.System, int, error) {
panic("not implemented")
}

func (s *mockSystemManager) GetSystemByID(context.Context, uuid.UUID) (*model.System, error) {
panic("not implemented")
}
Expand All @@ -400,9 +401,11 @@ func (s *mockSystemManager) RefreshSystemsData(context.Context) bool { return tr
func (s *mockSystemManager) LinkSystemAction(context.Context, uuid.UUID, cmkapi.SystemPatch) (*model.System, error) {
panic("not implemented")
}

func (s *mockSystemManager) GetRecoveryActions(context.Context, uuid.UUID) (cmkapi.SystemRecoveryAction, error) {
panic("not implemented")
}

func (s *mockSystemManager) SendRecoveryActions(
context.Context,
uuid.UUID,
Expand All @@ -411,6 +414,10 @@ func (s *mockSystemManager) SendRecoveryActions(
panic("not implemented")
}

func (s *mockSystemManager) GetFilters(context.Context) (cmkapi.SystemFilters, error) {
panic("not implemented")
}

func disconnectAllExistingSystems(t *testing.T, ctx context.Context, r repo.Repo) {
t.Helper()

Expand Down
9 changes: 9 additions & 0 deletions internal/repo/mock/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ func (r *InMemoryRepository) OffboardTenant(_ context.Context, schemaName string
return nil
}

func (r *InMemoryRepository) GetFilterOptions(
ctx context.Context,
resource repo.Resource,
columns []repo.Filter,
query repo.Query,
) error {
return nil
}

func assignList(result any, list []repo.Resource) error {
resultVal := reflect.ValueOf(result)
if resultVal.Kind() != reflect.Ptr {
Expand Down
6 changes: 6 additions & 0 deletions internal/repo/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,12 @@ type OrderField struct {
Direction OrderDirection
}

// Filter maps a struct field to a DB column for GetFilterOptions
type Filter struct {
Values *[]string
Column string
}

// NewQuery creates and returns a new empty query.
func NewQuery() *Query {
return &Query{
Expand Down
1 change: 1 addition & 0 deletions internal/repo/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Repo interface {
Transaction(ctx context.Context, txFunc TransactionFunc) error
Count(ctx context.Context, resource Resource, query Query) (int, error)
OffboardTenant(ctx context.Context, tenantID string) error
GetFilterOptions(ctx context.Context, resource Resource, columns []Filter, query Query) error
}

// Resource defines the interface for Resource operations.
Expand Down
Loading
Loading