Skip to content

Commit 3b58f60

Browse files
committed
domain: add the in-process domain
Signed-off-by: Ignasi Barrera <ignasi@tetrate.io>
1 parent 8dad3b6 commit 3b58f60

File tree

5 files changed

+143
-1
lines changed

5 files changed

+143
-1
lines changed

src/pkg/common/common.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strings"
1313

1414
oscalTypes "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-3"
15+
"github.com/defenseunicorns/lula/src/pkg/domains/inprocess"
1516
goversion "github.com/hashicorp/go-version"
1617
"k8s.io/apimachinery/pkg/util/yaml"
1718

@@ -155,6 +156,8 @@ func GetDomain(domain *Domain) (types.Domain, error) {
155156
return api.CreateApiDomain(domain.ApiSpec)
156157
case "file":
157158
return files.CreateDomain(domain.FileSpec)
159+
case "in-process":
160+
return inprocess.CreateDomain(domain.InProcessSpec)
158161
default:
159162
return nil, fmt.Errorf("domain is unsupported")
160163
}

src/pkg/common/schemas/validation.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@
5252
"enum": [
5353
"kubernetes",
5454
"api",
55-
"file"
55+
"file",
56+
"in-process"
5657
],
5758
"description": "The type of domain (Required)"
5859
},
@@ -462,6 +463,14 @@
462463
}
463464
}
464465
},
466+
"inprocess-spec": {
467+
"type": "object",
468+
"properties": {
469+
"resources": {
470+
"type": "object"
471+
}
472+
}
473+
},
465474
"provider": {
466475
"type": "object",
467476
"properties": {

src/pkg/common/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/defenseunicorns/go-oscal/src/pkg/uuid"
1111
oscalValidation "github.com/defenseunicorns/go-oscal/src/pkg/validation"
1212
oscalTypes "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-3"
13+
"github.com/defenseunicorns/lula/src/pkg/domains/inprocess"
1314
"sigs.k8s.io/yaml"
1415

1516
"github.com/defenseunicorns/lula/src/config"
@@ -104,6 +105,8 @@ type Domain struct {
104105
ApiSpec *api.ApiSpec `json:"api-spec,omitempty" yaml:"api-spec,omitempty"`
105106
// FileSpec is the specification for a File domain, required if type is file
106107
FileSpec *files.Spec `json:"file-spec,omitempty" yaml:"file-spec,omitempty"`
108+
// InProcessSpec is the specification for an InProcess domain, required if type is in-process
109+
InProcessSpec *inprocess.Spec `json:"inprocess-spec,omitempty" yaml:"inprocess-spec,omitempty"`
107110
}
108111

109112
type Provider struct {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) Tetrate, Inc 2025 All Rights Reserved.
2+
3+
package inprocess
4+
5+
import (
6+
"context"
7+
"errors"
8+
"fmt"
9+
"sync"
10+
)
11+
12+
var (
13+
ErrAlreadyRegistered = errors.New("already registered")
14+
ErrNotFound = errors.New("not found")
15+
16+
// globalRegistry is the global Registry of domain functions.
17+
globalRegistry = &Registry{
18+
functions: make(map[string]ResourcesFunction),
19+
}
20+
21+
_ ResourceRegistry = (*Registry)(nil)
22+
)
23+
24+
// ResourcesFunction is a function used to return the domain resources.
25+
type (
26+
ResourcesFunction func(context.Context) (any, error)
27+
28+
// ResourceRegistry is the interface for the global Registry of domain functions.
29+
ResourceRegistry interface {
30+
// Register the given domain function in the Registry.
31+
Register(name string, f ResourcesFunction) error
32+
// Unregister the given domain function from the Registry.
33+
Unregister(name string)
34+
// Run the domain function with the given name.
35+
Run(ctx context.Context, name string) (any, error)
36+
}
37+
)
38+
39+
// GlobalRegistry returns the global Registry of domain functions.
40+
func GlobalRegistry() ResourceRegistry { return globalRegistry }
41+
42+
// Registry is a thread-safe collection of domain functions.
43+
type Registry struct {
44+
mu sync.RWMutex
45+
functions map[string]ResourcesFunction
46+
}
47+
48+
// Register the given domain function in the Registry.
49+
func (r *Registry) Register(name string, f ResourcesFunction) error {
50+
r.mu.Lock()
51+
defer r.mu.Unlock()
52+
53+
if _, ok := r.functions[name]; ok {
54+
return fmt.Errorf("%w: %s", ErrAlreadyRegistered, name)
55+
}
56+
r.functions[name] = f
57+
return nil
58+
}
59+
60+
// Unregister the given domain function from the Registry.
61+
func (r *Registry) Unregister(name string) {
62+
r.mu.Lock()
63+
defer r.mu.Unlock()
64+
65+
delete(r.functions, name)
66+
}
67+
68+
// Run the domain function with the given name.
69+
func (r *Registry) Run(ctx context.Context, name string) (any, error) {
70+
r.mu.RLock()
71+
defer r.mu.RUnlock()
72+
73+
f, ok := r.functions[name]
74+
if !ok {
75+
return nil, fmt.Errorf("%w: %s", ErrNotFound, name)
76+
}
77+
return f(ctx)
78+
}

src/pkg/domains/inprocess/spec.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Tetrate, Inc 2025 All Rights Reserved.
2+
3+
package inprocess
4+
5+
import (
6+
"context"
7+
8+
"github.com/defenseunicorns/lula/src/types"
9+
)
10+
11+
type (
12+
// Spec configures the properties of the in process domain
13+
Spec struct {
14+
// Resources is a map of variables to function names to call
15+
Resources map[string]string `json:"resources" yaml:"resources"`
16+
}
17+
18+
// Domain is a structure that contains the domain type and the corresponding spec
19+
Domain struct {
20+
Spec *Spec `json:"spec" yaml:"spec"`
21+
registry ResourceRegistry
22+
}
23+
)
24+
25+
// CreateDomain creates a new in process domain.
26+
func CreateDomain(spec *Spec) (*Domain, error) {
27+
return &Domain{
28+
Spec: spec,
29+
registry: GlobalRegistry(),
30+
}, nil
31+
}
32+
33+
// IsExecutable implements Domain.
34+
func (d Domain) IsExecutable() bool { return false }
35+
36+
// GetResources implements Domain.
37+
func (d Domain) GetResources(ctx context.Context) (types.DomainResources, error) {
38+
resources := make(types.DomainResources)
39+
for variable, functionName := range d.Spec.Resources {
40+
res, err := d.registry.Run(ctx, functionName)
41+
if err != nil {
42+
return nil, err
43+
}
44+
resources[variable] = res
45+
}
46+
return resources, nil
47+
}
48+
49+
var _ types.Domain = (*Domain)(nil)

0 commit comments

Comments
 (0)