diff --git a/modules/distribution/cmd/distribution-tools/main.go b/modules/distribution/cmd/distribution-tools/main.go index e33c4ba95..e5cd3dee7 100644 --- a/modules/distribution/cmd/distribution-tools/main.go +++ b/modules/distribution/cmd/distribution-tools/main.go @@ -473,7 +473,7 @@ func tools(v *holder.Verbs, windows kept[holder.Window], callers func() (holder. func main() { base, _ := url.Parse("http://127.0.0.1:5001") - store := &holder.OCI{Base: base, Registry: os.Getenv("MESH_REGISTRY_REACH"), Upstream: &holder.Upstream{}} + store := &holder.OCI{Base: base, Upstream: &holder.Upstream{}} h := &holder.Holder{Objects: parts.BusObjects(holder.IncomingObjects), Builder: delivery.BuilderVersions{Ask: stdio.Ask}, Store: store, Say: say, Finding: finding, Transfers: parts.BusTransfers[holder.Opening](holder.TransfersState)} v := &holder.Verbs{Holder: h, Catalog: store, Holds: kept[holder.Hold]{state: "holds", key: holder.Hold.Key}, Mirrors: mirrors{}} diff --git a/modules/distribution/internal/holder/holder_test.go b/modules/distribution/internal/holder/holder_test.go index 130872e02..b9c152898 100644 --- a/modules/distribution/internal/holder/holder_test.go +++ b/modules/distribution/internal/holder/holder_test.go @@ -14,6 +14,8 @@ import ( "sync/atomic" "testing" "time" + + "git.novox.be/novox/mesh-sdk/go/catalogue" ) type memObjects map[string][]byte @@ -64,7 +66,7 @@ type fakeStore struct { func (s *fakeStore) Has(_, d string) (bool, error) { return s.has[d], nil } func (s *fakeStore) Put(t PublishRequest, parts map[string][]byte) (string, error) { s.put = append(s.put, parts) - return "registry.mesh/" + t.Name + "@" + t.Digest, nil + return t.Name + "@" + t.Digest, nil } func (s *fakeStore) Held(string, string, string) (string, bool, error) { return "", false, nil } @@ -118,7 +120,7 @@ func (c *fakeCatalog) Mirror(source, digest string) (string, error) { return c.Reference(src.Name(), digest), nil } func (c *fakeCatalog) Reference(name, digest string) string { - return "registry.mesh/" + name + "@" + digest + return name + "@" + digest } type memMirrors map[string]MirrorRequest @@ -213,6 +215,11 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) { if err != nil || !a.Ended || len(b.said) != 1 || b.said[0].event != EventPublished || b.said[0].body.Reference == "" { t.Fatalf("last chunk = %+v, %v; said %+v", a, err, b.said) } + // The reference's registry part is the seat's name, as a node-engine reads it back (ADR 0605 §9); nothing set on + // the process names a reach. + if seat, path, ok := catalogue.InRegistrySeat(b.said[0].body.Reference); !ok || seat != ArtifactSeat || path != "m/program@"+part.Digest { + t.Errorf("the published reference %q is not the seat's form", b.said[0].body.Reference) + } if len(b.h.Objects.(memObjects)) != 0 || len(b.h.Transfers.(memTransfers)) != 0 { t.Error("the transfer's chunks or key stayed after its end") } @@ -426,14 +433,14 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) { "manifests": []map[string]any{{"mediaType": mediaManifest, "digest": digestOf(img), "size": len(img)}}}) up.manifests[repo+":"+digestOf(idx)] = idx base, _ := url.Parse(sts.URL) - o := &OCI{Base: base, Registry: "registry.mesh:5000", Upstream: &Upstream{Scheme: "http"}} + o := &OCI{Base: base, Upstream: &Upstream{Scheme: "http"}} name := "upstream/" + host + "/" + repo store.blobs[name+"@"+digestOf(config)] = config // held already: not fetched again ref, err := o.Mirror(host+"/"+repo+":2", digestOf(idx)) if err != nil { t.Fatal(err) } - if want := "registry.mesh:5000/" + name + "@" + digestOf(idx); ref != want { + if want := name + "@" + digestOf(idx); ref != want { t.Errorf("reference %s, want %s", ref, want) } if store.manifests[name+":"+digestOf(idx)] == nil || store.manifests[name+":"+digestOf(img)] == nil || store.blobs[name+"@"+digestOf(layer)] == nil { @@ -460,7 +467,7 @@ func TestTheHolderOfTheTwoImageSeats(t *testing.T) { b := newBed(true) d := "sha256:" + strings.Repeat("c", 64) ref, err := b.v.Mirror(ImageSeat, "novox.mesh-build-image", MirrorRequest{Source: "docker.io/library/nats:2", Digest: d}) - want := "registry.mesh/upstream/docker.io/library/nats@" + d + want := "container-image-registry/upstream/docker.io/library/nats@" + d key := MirrorsKey("upstream/docker.io/library/nats", d) asked := b.v.Mirrors.(memMirrors) if err != nil || ref != want || len(b.said) != 0 || asked[key].By != "novox.mesh-build-image" { diff --git a/modules/distribution/internal/holder/mirror.go b/modules/distribution/internal/holder/mirror.go index cf12b7100..1e35f6da0 100644 --- a/modules/distribution/internal/holder/mirror.go +++ b/modules/distribution/internal/holder/mirror.go @@ -298,5 +298,6 @@ func (o *OCI) Mirror(source, digest string) (string, error) { return o.Reference(name, digest), nil } -// Reference is the seat's answer for name at digest: `/@`. -func (o *OCI) Reference(name, digest string) string { return o.Registry + "/" + name + "@" + digest } +// Reference is the path of the seat's answer for name at digest: `@`, the seat's name put before it by +// the holder (SeatReference). +func (o *OCI) Reference(name, digest string) string { return name + "@" + digest } diff --git a/modules/distribution/internal/holder/oci.go b/modules/distribution/internal/holder/oci.go index 3c3e30b36..6deee2222 100644 --- a/modules/distribution/internal/holder/oci.go +++ b/modules/distribution/internal/holder/oci.go @@ -12,12 +12,11 @@ import ( ) // OCI is the artifact store as the OCI distribution protocol answers it on its node's loopback, written by -// distribution's own process alone: the Store and the Catalog the verbs use. Registry is the reach the seat answers in a -// reference (`//@sha256:`, ADR 0605 §9). +// distribution's own process alone: the Store and the Catalog the verbs use. It answers a reference's path, +// `@sha256:`; the holder puts the seat's name before it (SeatReference, ADR 0605 §9). type OCI struct { - Base *url.URL - Registry string - Client *http.Client + Base *url.URL + Client *http.Client // Upstream reads the outside registries `mirror` copies from. Upstream *Upstream } @@ -162,7 +161,7 @@ func (o *OCI) Put(t PublishRequest, parts map[string][]byte) (string, error) { if err != nil { return "", err } - return o.Registry + "/" + t.Name + "@" + d, nil + return t.Name + "@" + d, nil default: if err := o.putBlob(t.Name, "sha256:"+sum([]byte(emptyConfig)), []byte(emptyConfig)); err != nil { return "", err @@ -184,7 +183,7 @@ func (o *OCI) Put(t PublishRequest, parts map[string][]byte) (string, error) { if _, err := o.putManifest(t.Name, ref, mediaManifest, m); err != nil { return "", err } - return o.Registry + "/" + t.Name + "@" + t.Digest, nil + return t.Name + "@" + t.Digest, nil } } @@ -197,7 +196,7 @@ func (o *OCI) Held(name, version, digest string) (string, bool, error) { if d != digest { return "", false, nil } - return o.Registry + "/" + name + "@" + d, true, nil + return name + "@" + d, true, nil } // Versions are name's tags. diff --git a/modules/distribution/internal/holder/transfer.go b/modules/distribution/internal/holder/transfer.go index 84dafb239..6df69f08e 100644 --- a/modules/distribution/internal/holder/transfer.go +++ b/modules/distribution/internal/holder/transfer.go @@ -128,13 +128,18 @@ type Builder interface { type Store interface { // Has says whether the store holds a blob of name. Has(name, digest string) (bool, error) - // Put stores a publish's parts under its name and version and answers the reference. + // Put stores a publish's parts under its name and version and answers the reference's path (SeatReference). Put(r PublishRequest, parts map[string][]byte) (reference string, err error) - // Held is the reference of name at version when the store already holds digest under it: a rebuild of a held + // Held is the reference's path of name at version when the store already holds digest under it: a rebuild of a held // fingerprint answers it and stores nothing. Held(name, version, digest string) (reference string, ok bool, err error) } +// SeatReference is a reference in the form the seat answers (novox/hq ADR 0605 §9): the seat's name, then the path the +// store answers (`@sha256:`), as catalogue.InRegistrySeat reads it back. Nothing set on the process names +// a reach: the seat's name is the registry part. +func SeatReference(seat, path string) string { return seat + "/" + path } + // Say says an event on a seat's family `.events`. type Say func(seat, event string, body Event) error @@ -194,7 +199,8 @@ func (h *Holder) receiver() *parts.Receiver[Opening] { return nil }, Store: func(t Transfer, held map[string][]byte) error { - ref, err := h.Store.Put(t.Shape.PublishRequest, held) + path, err := h.Store.Put(t.Shape.PublishRequest, held) + ref := SeatReference(t.Shape.Seat, path) if err != nil { reason := "the store did not take it: " + err.Error() return errors.Join(errors.New("refused: "+reason), h.refused(t, reason)) @@ -238,7 +244,7 @@ func (h *Holder) Publish(seat, caller string, r PublishRequest) (PublishAnswer, if ref, ok, err := h.Store.Held(r.Name, r.Version, r.Digest); err != nil { return PublishAnswer{}, fmt.Errorf("publish: the store cannot say whether it holds %s@%s: %w", r.Name, r.Version, err) } else if ok { - return PublishAnswer{Transfer: r.Transfer, Ended: true}, h.Say(seat, EventPublished, h.eventOf(seat, r, ref, "")) + return PublishAnswer{Transfer: r.Transfer, Ended: true}, h.Say(seat, EventPublished, h.eventOf(seat, r, SeatReference(seat, ref), "")) } } wants := make([]parts.Want, 0, len(r.Parts)) diff --git a/modules/distribution/internal/holder/verbs.go b/modules/distribution/internal/holder/verbs.go index 312be40df..30b1c7bd6 100644 --- a/modules/distribution/internal/holder/verbs.go +++ b/modules/distribution/internal/holder/verbs.go @@ -268,7 +268,7 @@ func (v *Verbs) Mirror(seat, caller string, r MirrorRequest) (string, error) { if err := v.Mirrors.Ask(MirrorsKey(src.Name(), r.Digest), r); err != nil { return "", fmt.Errorf("mirror: the copy of %s@%s cannot be taken on: %w", r.Source, r.Digest, err) } - return v.Catalog.Reference(src.Name(), r.Digest), nil + return SeatReference(seat, v.Catalog.Reference(src.Name(), r.Digest)), nil } // Mirrored runs one asked copy and says its outcome on the image seat's events: published with the reference, or @@ -281,7 +281,9 @@ func (v *Verbs) Mirrored(r MirrorRequest) error { } e := Event{Name: src.Name(), Kind: KindUpstream, Digest: r.Digest, Holder: Self, By: r.By, ID: r.ID} event := EventPublished - if e.Reference, err = v.Catalog.Mirror(r.Source, r.Digest); err != nil { + path, err := v.Catalog.Mirror(r.Source, r.Digest) + e.Reference = SeatReference(ImageSeat, path) + if err != nil { event, e.Reference, e.Reason = EventRefused, "", fmt.Sprintf("%s@%s was not copied: %v", r.Source, r.Digest, err) } if err := v.Say(ImageSeat, event, e); err != nil {