Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 19 additions & 6 deletions cmd/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import (
"path/filepath"

"github.com/go-kratos/kratos/v2/log"
"github.com/project-kessel/inventory-api/cmd/common"
"github.com/project-kessel/inventory-api/internal/data"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"

"github.com/project-kessel/inventory-api/cmd/common"
bizmodel "github.com/project-kessel/inventory-api/internal/biz/model"
"github.com/project-kessel/inventory-api/internal/data"
)

var schemaDir = "data/schema/resources"
Expand Down Expand Up @@ -40,8 +42,11 @@ func normalizeYAMLResourceType(yamlContent []byte) ([]byte, error) {

// Normalize the resources type if it exists
if resourceType, exists := yamlData["type"].(string); exists {
normalized := data.NormalizeResourceType(resourceType)
yamlData["type"] = normalized
rt, err := bizmodel.NewResourceType(resourceType)
if err != nil {
return nil, fmt.Errorf("invalid resource type in YAML: %w", err)
}
yamlData["type"] = data.NormalizeResourceType(rt).String()
}

// Convert back to YAML format
Expand Down Expand Up @@ -82,7 +87,11 @@ func preloadSchemas() error {
continue
}

resourceType := data.NormalizeResourceType(resource.Name())
rt, err := bizmodel.NewResourceType(resource.Name())
if err != nil {
continue
}
resourceType := data.NormalizeResourceType(rt).String()
resourcePath := filepath.Join(schemaDir, resource.Name())

// Load common resource data schema
Expand All @@ -109,7 +118,11 @@ func preloadSchemas() error {
continue
}

reporterType := data.NormalizeResourceType(reporter.Name())
rpt, err := bizmodel.NewReporterType(reporter.Name())
if err != nil {
continue
}
reporterType := data.NormalizeReporterType(rpt).String()
reporterPath := filepath.Join(reportersPath, reporter.Name())

// Encode reporter's config.yaml
Expand Down
8 changes: 4 additions & 4 deletions internal/biz/model/resource_delete_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ func (re ResourceDeleteEvent) UpdatedAt() *time.Time {
return &re.updatedAt
}

func (re ResourceDeleteEvent) ResourceType() string {
return re.resourceType.String()
func (re ResourceDeleteEvent) ResourceType() ResourceType {
return re.resourceType
}

func (re ResourceDeleteEvent) ReporterType() string {
return re.reporterId.reporterType.String()
func (re ResourceDeleteEvent) ReporterType() ReporterType {
return re.reporterId.reporterType
}

func (re ResourceDeleteEvent) ReporterInstanceId() string {
Expand Down
4 changes: 2 additions & 2 deletions internal/biz/model/resource_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package model

type ResourceEvent interface {
Id() ResourceId
ResourceType() string
ReporterType() string
ResourceType() ResourceType
ReporterType() ReporterType
ReporterInstanceId() string
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 2 need to be updated too. I'll do it in a follow on PR

LocalResourceId() string
WorkspaceId() *string
Expand Down
8 changes: 4 additions & 4 deletions internal/biz/model/resource_report_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ func (re ResourceReportEvent) UpdatedAt() *time.Time {
return &re.updatedAt
}

func (re ResourceReportEvent) ResourceType() string {
return re.resourceType.String()
func (re ResourceReportEvent) ResourceType() ResourceType {
return re.resourceType
}

func (re ResourceReportEvent) ReporterType() string {
return re.reporterId.reporterType.String()
func (re ResourceReportEvent) ReporterType() ReporterType {
return re.reporterId.reporterType
}

func (re ResourceReportEvent) ReporterInstanceId() string {
Expand Down
18 changes: 9 additions & 9 deletions internal/biz/model/schema_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,33 @@ const (
)

type ResourceSchema struct {
ResourceType string
ResourceType ResourceType
ValidationSchema ValidationSchema
}
type ReporterSchema struct {
ResourceType string
ReporterType string
ResourceType ResourceType
ReporterType ReporterType
ValidationSchema ValidationSchema
}
type SchemaRepository interface {
// GetResourceSchemas returns all the resourceTypes that have a ResourceSchema.
GetResourceSchemas(ctx context.Context) ([]string, error)
GetResourceSchemas(ctx context.Context) ([]ResourceType, error)
// CreateResourceSchema adds the ResourceSchema into the repository.
CreateResourceSchema(ctx context.Context, resource ResourceSchema) error
// GetResourceSchema returns the resource schema for the resourceType. Returns ResourceSchemaNotFound if the resource schema does not exist.
GetResourceSchema(ctx context.Context, resourceType string) (ResourceSchema, error)
GetResourceSchema(ctx context.Context, resourceType ResourceType) (ResourceSchema, error)
// UpdateResourceSchema updates the ResourceSchema for the resourceType. Returns ResourceSchemaNotFound if the resource schema does not exist.
UpdateResourceSchema(ctx context.Context, resource ResourceSchema) error
// DeleteResourceSchema deletes the ResourceSchema for the resourceType. Returns ResourceSchemaNotFound if the resource schema does not exist.
DeleteResourceSchema(ctx context.Context, resourceType string) error
DeleteResourceSchema(ctx context.Context, resourceType ResourceType) error
// GetReporterSchemas returns all the reporterTypes for resourceType. Returns ResourceSchemaNotFound if the resourceType does not exist.
GetReporterSchemas(ctx context.Context, resourceType string) ([]string, error)
GetReporterSchemas(ctx context.Context, resourceType ResourceType) ([]ReporterType, error)
// CreateReporterSchema adds the ReporterSchema into the repository. Returns ResourceSchemaNotFound if the resourceType does not exist.
CreateReporterSchema(ctx context.Context, resourceReporter ReporterSchema) error
// GetReporterSchema returns the ReporterSchema for the resourceType and reporterType. Returns ResourceSchemaNotFound if the resource schema does not exist and ReporterSchemaNotFound if the reporter schema does not exist for that resource.
GetReporterSchema(ctx context.Context, resourceType string, reporterType string) (ReporterSchema, error)
GetReporterSchema(ctx context.Context, resourceType ResourceType, reporterType ReporterType) (ReporterSchema, error)
// UpdateReporterSchema updates the ReporterSchema for the resourceType and reporterType. Returns ResourceSchemaNotFound if the resource schema does not exist and ReporterSchemaNotFound if the reporter schema does not exist for that resource.
UpdateReporterSchema(ctx context.Context, resourceReporter ReporterSchema) error
// DeleteReporterSchema deletes the ReporterSchema for the resourceType and reporterType. Returns ResourceSchemaNotFound if the resource schema does not exist and ReporterSchemaNotFound if the reporter schema does not exist for that resource.
DeleteReporterSchema(ctx context.Context, resourceType string, reporterType string) error
DeleteReporterSchema(ctx context.Context, resourceType ResourceType, reporterType ReporterType) error
}
18 changes: 9 additions & 9 deletions internal/biz/model/schema_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (sc *SchemaService) CalculateTuples(currentRepresentation, previousRepresen
}

// IsReporterForResource validates the resourceType and reporterType combination is valid. i.e. that there is a reporter that reports said resource.
func (sc *SchemaService) IsReporterForResource(ctx context.Context, resourceType string, reporterType string) (bool, error) {
func (sc *SchemaService) IsReporterForResource(ctx context.Context, resourceType ResourceType, reporterType ReporterType) (bool, error) {
if _, err := sc.schemaRepository.GetReporterSchema(ctx, resourceType, reporterType); err != nil {
if errors.Is(err, ResourceSchemaNotFound) || errors.Is(err, ReporterSchemaNotFound) {
return false, nil
Expand All @@ -65,14 +65,14 @@ func (sc *SchemaService) IsReporterForResource(ctx context.Context, resourceType
}

// CommonShallowValidate validates the common representation for a given resourceType.
func (sc *SchemaService) CommonShallowValidate(ctx context.Context, resourceType string, commonRepresentation map[string]interface{}) error {
func (sc *SchemaService) CommonShallowValidate(ctx context.Context, resourceType ResourceType, commonRepresentation map[string]interface{}) error {
resource, err := sc.schemaRepository.GetResourceSchema(ctx, resourceType)
if err != nil {
return fmt.Errorf("failed to load common representation schema for '%s': %w", resourceType, err)
return fmt.Errorf("failed to load common representation schema for '%s': %w", resourceType.String(), err)
}

if resource.ValidationSchema == nil {
return fmt.Errorf("no schema found for '%s'", resourceType)
return fmt.Errorf("no schema found for '%s'", resourceType.String())
}

hasCommonRepresentationData := len(commonRepresentation) > 0
Expand All @@ -85,14 +85,14 @@ func (sc *SchemaService) CommonShallowValidate(ctx context.Context, resourceType
if hasCommonRepresentationData {
return err
}
return fmt.Errorf("missing 'common' field in payload - schema for '%s' has required fields: %w", resourceType, err)
return fmt.Errorf("missing 'common' field in payload - schema for '%s' has required fields: %w", resourceType.String(), err)
}

return nil
}

// ReporterShallowValidate validates the specific reporter representation for a given resourceType/reporterType.
func (sc *SchemaService) ReporterShallowValidate(ctx context.Context, resourceType string, reporterType string, reporterRepresentation map[string]interface{}) error {
func (sc *SchemaService) ReporterShallowValidate(ctx context.Context, resourceType ResourceType, reporterType ReporterType, reporterRepresentation map[string]interface{}) error {
reporter, err := sc.schemaRepository.GetReporterSchema(ctx, resourceType, reporterType)
if err != nil {
return err
Expand All @@ -101,9 +101,9 @@ func (sc *SchemaService) ReporterShallowValidate(ctx context.Context, resourceTy
// Case 1: No schema found for resourceType:reporterType
if reporter.ValidationSchema == nil {
if len(reporterRepresentation) > 0 {
return fmt.Errorf("no schema found for '%s:%s', but reporter representation was provided. Submission is not allowed", resourceType, reporterType)
return fmt.Errorf("no schema found for '%s:%s', but reporter representation was provided. Submission is not allowed", resourceType.String(), reporterType.String())
}
sc.Log.Debugf("no schema found for %s:%s, treating as abstract reporter representation", resourceType, reporterType)
sc.Log.Debugf("no schema found for %s:%s, treating as abstract reporter representation", resourceType.String(), reporterType.String())
return nil
}

Expand All @@ -119,7 +119,7 @@ func (sc *SchemaService) ReporterShallowValidate(ctx context.Context, resourceTy
}

// If schema has validation errors but reporterRepresentation is nil/empty, that's an error
return fmt.Errorf("missing 'reporter' field in payload - schema for '%s:%s' has required fields: %w", resourceType, reporterType, err)
return fmt.Errorf("missing 'reporter' field in payload - schema for '%s:%s' has required fields: %w", resourceType.String(), reporterType.String(), err)
}

return nil
Expand Down
8 changes: 4 additions & 4 deletions internal/biz/model_legacy/outboxevents.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,24 +132,24 @@ func newResourceEvent(operationType bizmodel.EventOperationType, resourceEvent *

return &ResourceEvent{
Specversion: "1.0",
Type: makeEventType(eventType, resourceEvent.ResourceType(), string(operationType.OperationType())),
Type: makeEventType(eventType, resourceEvent.ResourceType().String(), string(operationType.OperationType())),
Source: "", // TODO: inventory uri
Id: eventId.String(),
Subject: makeEventSubject(eventType, resourceEvent.ResourceType(), resourceEvent.Id().String()),
Subject: makeEventSubject(eventType, resourceEvent.ResourceType().String(), resourceEvent.Id().String()),
Time: reportedTime,
DataContentType: "application/json",
Data: EventResourceData{
Metadata: EventResourceMetadata{
Id: resourceEvent.Id().String(),
ResourceType: resourceEvent.ResourceType(),
ResourceType: resourceEvent.ResourceType().String(),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
DeletedAt: deletedAt,
WorkspaceId: resourceEvent.WorkspaceId(),
},
ReporterData: EventResourceReporter{
ReporterInstanceId: resourceEvent.ReporterInstanceId(),
ReporterType: resourceEvent.ReporterType(),
ReporterType: resourceEvent.ReporterType().String(),
ConsoleHref: bizmodel.SerializeStringPtr(resourceEvent.ConsoleHref()),
ApiHref: resourceEvent.ApiHref(),
LocalResourceId: resourceEvent.LocalResourceId(),
Expand Down
8 changes: 4 additions & 4 deletions internal/biz/model_legacy/outboxevents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ func assertTupleEventFromDomainEvent(t *testing.T, resourceEvent bizmodel.Resour
assert.Nil(t, err)

key := tupleEvent.ReporterResourceKey()
assert.Equal(t, resourceEvent.ResourceType(), key.ResourceType().String())
assert.Equal(t, resourceEvent.ReporterType(), key.ReporterType().String())
assert.Equal(t, resourceEvent.ResourceType(), key.ResourceType())
assert.Equal(t, resourceEvent.ReporterType(), key.ReporterType())
assert.Equal(t, resourceEvent.ReporterInstanceId(), key.ReporterInstanceId().String())
assert.Equal(t, resourceEvent.LocalResourceId(), key.LocalResourceId().String())

Expand Down Expand Up @@ -146,10 +146,10 @@ func assertResourceEventFromDomainEvent(t *testing.T, operation bizmodel.EventOp
var data EventResourceData
err = json.Unmarshal(dataBytes, &data)
assert.Nil(t, err)
assert.Equal(t, resourceEvent.ResourceType(), data.Metadata.ResourceType)
assert.Equal(t, resourceEvent.ResourceType().String(), data.Metadata.ResourceType)
assert.Equal(t, resourceEvent.WorkspaceId(), data.Metadata.WorkspaceId)
assert.Equal(t, resourceEvent.ReporterInstanceId(), data.ReporterData.ReporterInstanceId)
assert.Equal(t, resourceEvent.ReporterType(), data.ReporterData.ReporterType)
assert.Equal(t, resourceEvent.ReporterType().String(), data.ReporterData.ReporterType)
assert.Equal(t, bizmodel.SerializeStringPtr(resourceEvent.ConsoleHref()), data.ReporterData.ConsoleHref)
assert.Equal(t, resourceEvent.ApiHref(), data.ReporterData.ApiHref)
assert.Equal(t, resourceEvent.LocalResourceId(), data.ReporterData.LocalResourceId)
Expand Down
18 changes: 4 additions & 14 deletions internal/biz/usecase/resources/resource_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -588,33 +588,23 @@ func (uc *Usecase) enforceMetaAuthzObject(ctx context.Context, relation metaauth
// It checks that the reporter is allowed for the resource type,
// and validates both reporter and common representations.
func (uc *Usecase) validateReportResourceCommand(ctx context.Context, cmd ReportResourceCommand) error {
resourceType := cmd.ResourceType.String()
reporterType := cmd.ReporterType.String()

if resourceType == "" {
return fmt.Errorf("missing 'type' field")
}
if reporterType == "" {
return fmt.Errorf("missing 'reporterType' field")
}

if isReporter, err := uc.schemaService.IsReporterForResource(ctx, resourceType, reporterType); !isReporter {
if isReporter, err := uc.schemaService.IsReporterForResource(ctx, cmd.ResourceType, cmd.ReporterType); !isReporter {
if err != nil {
return err
}
return fmt.Errorf("reporter %s does not report resource types: %s", reporterType, resourceType)
return fmt.Errorf("reporter %s does not report resource types: %s", cmd.ReporterType.String(), cmd.ResourceType.String())
}

if cmd.ReporterRepresentation != nil {
sanitizedReporterRepresentation := removeNulls(map[string]interface{}(*cmd.ReporterRepresentation))
if err := uc.schemaService.ReporterShallowValidate(ctx, resourceType, reporterType, sanitizedReporterRepresentation); err != nil {
if err := uc.schemaService.ReporterShallowValidate(ctx, cmd.ResourceType, cmd.ReporterType, sanitizedReporterRepresentation); err != nil {
return err
}
}

if cmd.CommonRepresentation != nil {
commonRepresentation := map[string]interface{}(*cmd.CommonRepresentation)
if err := uc.schemaService.CommonShallowValidate(ctx, resourceType, commonRepresentation); err != nil {
if err := uc.schemaService.CommonShallowValidate(ctx, cmd.ResourceType, commonRepresentation); err != nil {
return err
}
}
Expand Down
Loading
Loading