Skip to content

Commit

Permalink
engine: Vet module instance at build-time
Browse files Browse the repository at this point in the history
Signed-off-by: Stefan Prodan <[email protected]>
  • Loading branch information
stefanprodan committed Oct 20, 2023
1 parent 80e99ec commit 6f4dec9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 24 deletions.
6 changes: 3 additions & 3 deletions api/v1alpha1/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ const (
// APIVersionSelector is the CUE path for the Timoni's API version.
APIVersionSelector Selector = "timoni.apiVersion"

// InstanceSelector is the CUE path for the Timoni's instance.
InstanceSelector Selector = "timoni.instance"

// ApplySelector is the CUE path for the Timoni's apply resource sets.
ApplySelector Selector = "timoni.apply"

// ConfigValuesSelector is the CUE path for the Timoni's instance config values.
ConfigValuesSelector Selector = "timoni.instance.config"

// ValuesSelector is the CUE path for the Timoni's module values.
ValuesSelector Selector = "values"
)
Expand Down
49 changes: 28 additions & 21 deletions internal/engine/module_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,10 @@ func (b *ModuleBuilder) SetVersionInfo(moduleVersion, kubeVersion string) {
}
}

// Build builds a CUE instances for the specified package and returns the CUE value.
func (b *ModuleBuilder) Build() (cue.Value, error) {
// Build builds the Timoni instance for the specified module and returns its CUE value.
// If the instance validation fails, the returned error may represent more than one error,
// retrievable with errors.Errors.
func (b *ModuleBuilder) Build(tags ...string) (cue.Value, error) {
var value cue.Value
cfg := &load.Config{
ModuleRoot: b.moduleRoot,
Expand All @@ -166,22 +168,37 @@ func (b *ModuleBuilder) Build() (cue.Value, error) {
},
}

ix := load.Instances([]string{}, cfg)
if len(ix) == 0 {
if len(tags) > 0 {
cfg.Tags = append(cfg.Tags, tags...)
}

modInstances := load.Instances([]string{}, cfg)
if len(modInstances) == 0 {
return value, fmt.Errorf("no instances found")
}

inst := ix[0]
if inst.Err != nil {
return value, fmt.Errorf("instance error: %w", inst.Err)
modInstance := modInstances[0]
if modInstance.Err != nil {
return value, fmt.Errorf("instance error: %w", modInstance.Err)
}

modValue := b.ctx.BuildInstance(modInstance)
if modValue.Err() != nil {
return value, modValue.Err()
}

// Extract the Timoni instance from the build value.
instance := modValue.LookupPath(cue.ParsePath(apiv1.InstanceSelector.String()))
if instance.Err() != nil {
return modValue, fmt.Errorf("lookup %s failed: %w", apiv1.InstanceSelector, instance.Err())
}

v := b.ctx.BuildInstance(inst)
if v.Err() != nil {
return value, v.Err()
// Validate the Timoni instance which should be concrete and final.
if err := instance.Validate(cue.Concrete(true), cue.Final()); err != nil {
return modValue, err
}

return v, nil
return modValue, nil
}

// GetAPIVersion returns the list of API version of the Timoni's CUE definition.
Expand Down Expand Up @@ -250,13 +267,3 @@ func (b *ModuleBuilder) GetModuleName() (string, error) {

return mod, nil
}

// GetConfigValues extracts the instance config values from the build result.
func (b *ModuleBuilder) GetConfigValues(value cue.Value) (string, error) {
expr := value.LookupPath(cue.ParsePath(apiv1.ConfigValuesSelector.String()))
if expr.Err() != nil {
return "", fmt.Errorf("lookup %s failed: %w", apiv1.ConfigValuesSelector, expr.Err())
}

return fmt.Sprintf("%v", expr.Eval()), nil
}

0 comments on commit 6f4dec9

Please sign in to comment.