Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add client implementation of distribution interface #387

Merged
merged 26 commits into from
May 20, 2015

Conversation

dmcgowan
Copy link
Collaborator

Adds functionality to create a Repository client which connects to a remote endpoint.

A few functions are yet to be implemented.

Authorizer is an interface to allow for passing different credential types but abstracting that from the rest of the client code. It may make sense to split this out to somewhere else. To follow the client logic today, getting an Authorizer will ping a registry endpoint to get the auth challenge list, then the implementation of Authorizer will take care of either attaching the credentials directly or hitting a token server.

As part of this change, I also want to get rid of the old client interface as well as break apart the repository file into multiple files.

@stevvooe stevvooe added this to the Registry/2.1 milestone Apr 27, 2015
@RichardScothern RichardScothern mentioned this pull request Apr 28, 2015
12 tasks
@dmcgowan dmcgowan force-pushed the registry-client-update branch 2 times, most recently from 754ee85 to 2334dbb Compare May 4, 2015 23:52
)

// NewRepositoryClient creates a new Repository for the given repository name and endpoint
func NewRepositoryClient(ctx context.Context, name string, endpoint *RepositoryEndpoint) (distribution.Repository, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmcgowan I guess this could be called NewRepository since it's returning a new repository. wdyt?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed

Scheme string
Parameters map[string]string
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a companion function "ParseAuthChallenge" that will parse the header if this is an exported type.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this is even exposed, I will trim down some as this shouldn't be needed outside this package.

@dmcgowan
Copy link
Collaborator Author

dmcgowan commented May 8, 2015

Made updates as suggested. Can likely move Transport and Authorizer into a subpackage to focus the client package interface more. The interface is relatively light except for all the Error types introduced.

n, err = rd.Read(p)
hl.offset += int64(n)

// Simulate io.EOR error if we reach filesize.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/EOR/EOF

@stevvooe
Copy link
Collaborator

@dmcgowan Here's a good test for Authorizor and Transport: can they be used without the rest of the implementation to correctly communicate with a docker endpoint?

@dmcgowan
Copy link
Collaborator Author

@stevvooe the Transport and Authorizer interface, yes it could. The individual implementations for AuthenticationHandler could also be used generically. However the implementation of Authorizer which uses the handlers is not generic as it expects to get a set of authentication challenges when hitting the "v2" endpoint.

@dmcgowan dmcgowan changed the title WIP: Add client implementation of distribution interface Add client implementation of distribution interface May 11, 2015
@dmcgowan
Copy link
Collaborator Author

Removed this WIP flag, this PR is ready for more intensive review. There are a few TODOs still in the code that I do not think are merge blockers.

return ioutil.NopCloser(bytes.NewReader([]byte{})), nil
}

blobURL, err := hl.ub.BuildBlobURL(hl.name, hl.digest)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmcgowan @stevvooe

It would be so much better to have an exported constructor that takes a static url string and an http client to make it very generic so that I can reuse it:

func NewHttpReadSeeker(client *http.Client, url string) io.ReadSeeker {
    return *httpLayer{...}
}

you shouldn't need to embed *layers

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting rebase now onto the refactor branch, will re-address your comment after.

What do you see as the generic use case for httpLayer?

@dmcgowan
Copy link
Collaborator Author

@stevvooe simplified interface down to func NewRepository(ctx context.Context, name, endpoint string, transport http.RoundTripper) (distribution.Repository, error)

The custom transport, modifier interface, and authentication handlers are now completely separated and should likely be moved into a sub package.

if err != nil {
return nil, err
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defer resp.Body.Close()

}

type blobStatter struct {
*repository
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While embedding was heavily used in the storage package, I found it to be more clear to outline the actual dependencies of the blob statter. It makes it easier to identify bad patterns, especially in an evolving code base.

This depends on ub and client.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

Update comments and TODOs
Fix switch style
Updated parse http response to take in reader
Add Cancel implementation
Update blobstore variable name

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
Each type no longer requires holding a reference to repository.
Added implementation for signatures get.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
@stevvooe
Copy link
Collaborator

I'm going to give my LGTM on this.

There may be some tweaks we want to do but this is good enough for what is required now.

}

return tagsResponse.Tags, nil
case http.StatusNotFound:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmcgowan isn't a 401 expected? currently 401 goes through handleErrorResponse which returns an "unexpected" http error. It breaks downloading private images without being logged in.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, when nginx is serving up the basic auth it will likely get caught as "unexpected". I think the proper solution will be to just handle 401 in the handleErrorResponse function.

Add check for unauthorized error code and explicitly set the error code if the content could not be parsed.
Updated repository test for unauthorized tests and nit feedback.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
The transport package no longer requires importing distribution for the ReadSeekCloser, instead declares its own.
Added comments on the Authenication handler in session.
Added todo on http seek reader to highlight its lack of belonging to the client transport.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
@dmcgowan
Copy link
Collaborator Author

Added a few more commits to address comments and 401 errors.

I plan to have follow up commits to address

  • token logic refactor to registry/auth/token
  • ping attempt on redirected endpoints

Changes behavior so ping doesn't happen if /v2/ is anywhere in a request path, but instead only at the beginning. This fixes attempts to ping on redirected URLs.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
@dmcgowan
Copy link
Collaborator Author

Pushed a fix to the issue I described, with a comment highlighting its current behavior and ideal behavior

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
@tiborvass
Copy link
Contributor

LGTM

1 similar comment
@stevvooe
Copy link
Collaborator

LGTM

stevvooe added a commit that referenced this pull request May 20, 2015
Add client implementation of distribution interface
@stevvooe stevvooe merged commit ea54a55 into distribution:master May 20, 2015
@RichardScothern
Copy link
Contributor

LGTM

On Wed, May 20, 2015 at 3:54 PM, Stephen Day notifications@github.com
wrote:

LGTM


Reply to this email directly or view it on GitHub
#387 (comment).

thaJeztah pushed a commit to thaJeztah/distribution that referenced this pull request Apr 22, 2021
Add client implementation of distribution interface
thaJeztah pushed a commit to thaJeztah/distribution that referenced this pull request Jan 19, 2022
Add client implementation of distribution interface
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants