Say that a module is unbuilt, rather than letting a machine call it malformed
A container naming an artifact is a module saying the mesh builds this. Until a build publishes one there is nothing to run — and what reached the machine was an unresolved field, which its language has no room for, so it refused the whole declaration and reported that a container does not use "artifact". That reads as a broken manifest. It is not broken, it is unbuilt, and only the mesh can tell those apart. Found by the four-machine bed, which assigns modules the mesh has not built.
This commit is contained in:
@@ -456,6 +456,11 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
|
|||||||
if err := pinned(copied, m.Module); err != nil {
|
if err := pinned(copied, m.Module); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// And the other half of the same question: an image nobody has published yet is named
|
||||||
|
// by an artifact rather than by a placeholder digest, and is just as unrunnable.
|
||||||
|
if err := built(copied, m.Module); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
publishedOn(copied, m.Module, with)
|
publishedOn(copied, m.Module, with)
|
||||||
copied["id"] = m.Module + "." + fmt.Sprint(resource["id"])
|
copied["id"] = m.Module + "." + fmt.Sprint(resource["id"])
|
||||||
// A service saying what it reflects names resources within its own module, so those
|
// A service saying what it reflects names resources within its own module, so those
|
||||||
@@ -887,6 +892,30 @@ func pinned(resource map[string]any, module string) error {
|
|||||||
module, resource["id"])
|
module, resource["id"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// built refuses a container that still names an artifact nobody has made.
|
||||||
|
//
|
||||||
|
// **Said here, by the thing that knows what "artifact" means.** A container naming an artifact is
|
||||||
|
// a module saying "the mesh builds this"; the field is resolved into an image when a build
|
||||||
|
// publishes one, and until then there is nothing to run. A host receiving it refuses the whole
|
||||||
|
// declaration — correctly, since its language has no such field — but what it can say is that a
|
||||||
|
// container does not use "artifact", which tells a reader the manifest is malformed. It is not:
|
||||||
|
// it is unbuilt, which is a different problem with a different fix, and only the mesh is in a
|
||||||
|
// position to tell them apart (novox/hq ADR 0073).
|
||||||
|
func built(resource map[string]any, module string) error {
|
||||||
|
if fmt.Sprint(resource["type"]) != "container" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
artifact, ok := resource["artifact"].(string)
|
||||||
|
if !ok || artifact == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf(
|
||||||
|
"%s has not been built for this mesh: %v is its %q artifact, and no build has published "+
|
||||||
|
"one. Build it — `build <repository> --path <path>` — and the module will name what "+
|
||||||
|
"came out instead",
|
||||||
|
module, resource["id"], artifact)
|
||||||
|
}
|
||||||
|
|
||||||
// publishedOn puts the machine's own port on the outside of a container's mapping.
|
// publishedOn puts the machine's own port on the outside of a container's mapping.
|
||||||
//
|
//
|
||||||
// **A module writes the port the software uses; the mesh says where the machine puts it**
|
// **A module writes the port the software uses; the mesh says where the machine puts it**
|
||||||
|
|||||||
Reference in New Issue
Block a user