A node applies one module's composition at a time, so each carries only its own module's resources, checked resource by resource as the node-engine reads them, and its digest follows its content alone (ADR 0539 clauses 1 and 4). The fixtures are the controller's plan answers for ace and g14, their sealed resources taken out.
48 lines
1.9 KiB
Go
48 lines
1.9 KiB
Go
package declaration
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// ParseResource reads one resource as Parse reads each of a declaration's resources: by its type, strictly, refusing
|
|
// a field its kind does not use and anything its kind refuses, and never an action (the link may not carry one, ADR
|
|
// 0005). It judges the resource alone: what Parse judges across resources (an opening on a node not adopted, the
|
|
// files the provisioner fills, what replaces what) is for the whole a node applies (novox/hq ADR 0539 clause 1: a
|
|
// composition is one module's resources, and a node applies its compositions together with its own key).
|
|
func ParseResource(raw json.RawMessage) (Resource, error) {
|
|
var head struct {
|
|
ID string `json:"id"`
|
|
Type Type `json:"type"`
|
|
}
|
|
if err := json.Unmarshal(raw, &head); err != nil {
|
|
return nil, &RefusalError{Problems: []string{"not a resource: " + err.Error()}}
|
|
}
|
|
where := "resource"
|
|
if head.ID == "" {
|
|
return nil, &RefusalError{Problems: []string{where + ": no id. Identity is what lets the host know this is " +
|
|
"the same resource it applied last time"}}
|
|
}
|
|
where = fmt.Sprintf("resource %q", head.ID)
|
|
resource := newOf(head.Type)
|
|
if resource == nil {
|
|
return nil, &RefusalError{Problems: []string{fmt.Sprintf("%s: unknown type %q. This host understands %s",
|
|
where, head.Type, vocabulary())}}
|
|
}
|
|
if unknown := unknownFields(raw, resource); len(unknown) > 0 {
|
|
var problems []string
|
|
for _, field := range unknown {
|
|
problems = append(problems, fmt.Sprintf("%s: a %s does not use %q, and it is set. Refused rather "+
|
|
"than ignored", where, head.Type, field))
|
|
}
|
|
return nil, &RefusalError{Problems: problems}
|
|
}
|
|
if err := json.Unmarshal(raw, resource); err != nil {
|
|
return nil, &RefusalError{Problems: []string{fmt.Sprintf("%s: %s", where, err)}}
|
|
}
|
|
if problems := resource.validate(where, false); len(problems) > 0 {
|
|
return nil, &RefusalError{Problems: problems}
|
|
}
|
|
return resource, nil
|
|
}
|