Catalog for V2 API Implementation
This change adds a basic catalog endpoint to the API, which returns a list, or partial list, of all of the repositories contained in the registry. Calls to this endpoint are somewhat expensive, as every call requires walking a large part of the registry. Instead, to maintain a list of repositories, you would first call the catalog endpoint to get an initial list, and then use the events API to maintain any future repositories. Signed-off-by: Patrick Devine <patrick.devine@docker.com>
This commit is contained in:
parent
0790a298ed
commit
f3207e76c8
11 changed files with 568 additions and 1 deletions
|
@ -60,6 +60,85 @@ func TestCheckAPI(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCatalogAPI(t *testing.T) {
|
||||
env := newTestEnv(t)
|
||||
|
||||
values := url.Values{"last": []string{""}, "n": []string{"100"}}
|
||||
|
||||
catalogURL, err := env.builder.BuildCatalogURL(values)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error building catalog url: %v", err)
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// try to get an empty catalog
|
||||
resp, err := http.Get(catalogURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error issuing request: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "issuing catalog api check", resp, http.StatusOK)
|
||||
|
||||
var ctlg struct {
|
||||
Repositories []string `json:"repositories"`
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
if err := dec.Decode(&ctlg); err != nil {
|
||||
t.Fatalf("error decoding fetched manifest: %v", err)
|
||||
}
|
||||
|
||||
// we haven't pushed anything to the registry yet
|
||||
if ctlg.Repositories != nil {
|
||||
t.Fatalf("repositories has unexpected values")
|
||||
}
|
||||
|
||||
if resp.Header.Get("Link") != "" {
|
||||
t.Fatalf("repositories has more data when none expected")
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// push something to the registry and try again
|
||||
imageName := "foo/bar"
|
||||
createRepository(env, t, imageName, "sometag")
|
||||
|
||||
resp, err = http.Get(catalogURL)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error issuing request: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
checkResponse(t, "issuing catalog api check", resp, http.StatusOK)
|
||||
|
||||
dec = json.NewDecoder(resp.Body)
|
||||
if err = dec.Decode(&ctlg); err != nil {
|
||||
t.Fatalf("error decoding fetched manifest: %v", err)
|
||||
}
|
||||
|
||||
if len(ctlg.Repositories) != 1 {
|
||||
t.Fatalf("repositories has unexpected values")
|
||||
}
|
||||
|
||||
if !contains(ctlg.Repositories, imageName) {
|
||||
t.Fatalf("didn't find our repository '%s' in the catalog", imageName)
|
||||
}
|
||||
|
||||
if resp.Header.Get("Link") != "" {
|
||||
t.Fatalf("repositories has more data when none expected")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func contains(elems []string, e string) bool {
|
||||
for _, elem := range elems {
|
||||
if elem == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestURLPrefix(t *testing.T) {
|
||||
config := configuration.Configuration{
|
||||
Storage: configuration.Storage{
|
||||
|
@ -869,3 +948,60 @@ func checkErr(t *testing.T, err error, msg string) {
|
|||
t.Fatalf("unexpected error %s: %v", msg, err)
|
||||
}
|
||||
}
|
||||
|
||||
func createRepository(env *testEnv, t *testing.T, imageName string, tag string) {
|
||||
unsignedManifest := &manifest.Manifest{
|
||||
Versioned: manifest.Versioned{
|
||||
SchemaVersion: 1,
|
||||
},
|
||||
Name: imageName,
|
||||
Tag: tag,
|
||||
FSLayers: []manifest.FSLayer{
|
||||
{
|
||||
BlobSum: "asdf",
|
||||
},
|
||||
{
|
||||
BlobSum: "qwer",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Push 2 random layers
|
||||
expectedLayers := make(map[digest.Digest]io.ReadSeeker)
|
||||
|
||||
for i := range unsignedManifest.FSLayers {
|
||||
rs, dgstStr, err := testutil.CreateRandomTarFile()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("error creating random layer %d: %v", i, err)
|
||||
}
|
||||
dgst := digest.Digest(dgstStr)
|
||||
|
||||
expectedLayers[dgst] = rs
|
||||
unsignedManifest.FSLayers[i].BlobSum = dgst
|
||||
|
||||
uploadURLBase, _ := startPushLayer(t, env.builder, imageName)
|
||||
pushLayer(t, env.builder, imageName, dgst, uploadURLBase, rs)
|
||||
}
|
||||
|
||||
signedManifest, err := manifest.Sign(unsignedManifest, env.pk)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error signing manifest: %v", err)
|
||||
}
|
||||
|
||||
payload, err := signedManifest.Payload()
|
||||
checkErr(t, err, "getting manifest payload")
|
||||
|
||||
dgst, err := digest.FromBytes(payload)
|
||||
checkErr(t, err, "digesting manifest")
|
||||
|
||||
manifestDigestURL, err := env.builder.BuildManifestURL(imageName, dgst.String())
|
||||
checkErr(t, err, "building manifest url")
|
||||
|
||||
resp := putManifest(t, "putting signed manifest", manifestDigestURL, signedManifest)
|
||||
checkResponse(t, "putting signed manifest", resp, http.StatusAccepted)
|
||||
checkHeaders(t, resp, http.Header{
|
||||
"Location": []string{manifestDigestURL},
|
||||
"Docker-Content-Digest": []string{dgst.String()},
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue