Files
mesh-host/internal/compose/resolution/artifacts.go
T

84 lines
3.7 KiB
Go

package resolution
import (
"fmt"
"strings"
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
)
// artifactsInto composes the artifact store's address into a resource's `image` and `source`.
//
// **Composed here, at the last moment before a machine, and stored nowhere.** A kept reference is
// routed through the store as this network reaches it now. A reference recorded with an address
// before references were kept without one is re-routed the same way — but only when the mesh
// built it (`with.Built` names every `<module>/<artifact>` it has), because a module may run an
// image from a public registry under its own name and that one is exactly where it says.
//
// A kept reference with no store to route it through is refused: sent as it is, the runtime would
// refuse the scheme on the machine, one push away from the reason.
//
// **What this does not reach: the images genesis pinned.** The installer builds the control plane
// and the builder before the mesh exists, pushes them itself and pins their manifests to
// `<registry>:<port>/mesh-controller@…` and `<registry>:<port>/mesh-builder@…` — single-segment
// repositories with no build record, so `with.Built` does not name them and they are left as
// written until each is rebuilt through the mesh, which records it by digest and path. Until then
// a registry that moves strands exactly those two on a recreate, and the control plane's is the
// one that cannot be repaired through the mesh. Rebuild both through `build` before moving the
// store (novox/hq 04-ISSUES/102, finding F4).
func artifactsInto(resource map[string]any, module string, with mcat.Rendering) error {
for _, key := range []string{"image", "source"} {
written, ok := resource[key].(string)
if !ok {
continue
}
if _, kept := mcat.InArtifactStore(written); kept {
if with.ArtifactStore == "" {
return fmt.Errorf(
"%s's %v names %s, which is in the mesh's artifact store, and this mesh has no "+
"artifact store on its network to fetch it from — nothing assigned offers "+
"%s, or the machine offering it is not on the private network",
module, resource["id"], written, mcat.ArtifactStoreProvision)
}
resource[key] = mcat.Routed(written, with.ArtifactStore)
imageSeatInto(resource, key, with)
continue
}
if with.ArtifactStore == "" {
continue
}
recorded := mcat.Recorded(written)
if recorded == written {
continue
}
path, _ := mcat.InArtifactStore(recorded)
repository := path
if at := strings.IndexAny(path, "@"); at >= 0 {
repository = path[:at]
} else if blobs := strings.Index(path, "/blobs/"); blobs >= 0 {
repository = path[:blobs]
}
if with.Built[repository] {
resource[key] = mcat.Routed(recorded, with.ArtifactStore)
imageSeatInto(resource, key, with)
}
}
return nil
}
// artifactSeat is the seat an image is routed through: the artifact store's (the registries' four seats follow as the
// references name them).
const artifactSeat = "mesh-artifact-store"
// imageSeatInto writes beside a container's routed image the seat the reference came through and that seat's holder (design 51
// *distribution's first delivery*, issue 1966 ENG-10), so the node-engine finds by the declaration whom a failed pull waits
// on, never by a module's name. Neither is part of what a container is: a declaration composed again for a new holder
// replaces no container. Nothing is written where the holder is not on record, or for a resource that is no container.
func imageSeatInto(resource map[string]any, key string, with mcat.Rendering) {
if key != "image" || resource["type"] != "container" || with.SeatHolder[artifactSeat] == "" {
return
}
resource["image-seat"] = artifactSeat
resource["image-holder"] = with.SeatHolder[artifactSeat]
}