Skip to content

Commit

Permalink
Make NewAuthenticatedClient take a version URL
Browse files Browse the repository at this point in the history
This enables creating a controller without doing version probing.
  • Loading branch information
babbageclunk committed Apr 3, 2017
1 parent 31d8415 commit 34256e9
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 31 deletions.
32 changes: 18 additions & 14 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"mime/multipart"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -265,31 +266,34 @@ func (signer anonSigner) OAuthSign(request *http.Request) error {
// *anonSigner implements the OAuthSigner interface.
var _ OAuthSigner = anonSigner{}

func composeAPIURL(BaseURL string, apiVersion string) (*url.URL, error) {
// AddAPIVersionToURL will add the version/<version>/ suffix to the
// given URL, handling trailing slashes. It shouldn't be called with a
// URL that already includes a version.
func AddAPIVersionToURL(BaseURL, apiVersion string) string {
baseurl := EnsureTrailingSlash(BaseURL)
apiurl := fmt.Sprintf("%sapi/%s/", baseurl, apiVersion)
return url.Parse(apiurl)
return fmt.Sprintf("%sapi/%s/", baseurl, apiVersion)
}

// NewAnonymousClient creates a client that issues anonymous requests.
// BaseURL should refer to the root of the MAAS server path, e.g.
// http://my.maas.server.example.com/MAAS/
// apiVersion should contain the version of the MAAS API that you want to use.
func NewAnonymousClient(BaseURL string, apiVersion string) (*Client, error) {
parsedBaseURL, err := composeAPIURL(BaseURL, apiVersion)
versionedURL := AddAPIVersionToURL(BaseURL, apiVersion)
parsedURL, err := url.Parse(versionedURL)
if err != nil {
return nil, err
}
return &Client{Signer: &anonSigner{}, APIURL: parsedBaseURL}, nil
return &Client{Signer: &anonSigner{}, APIURL: parsedURL}, nil
}

// NewAuthenticatedClient parses the given MAAS API key into the individual
// OAuth tokens and creates an Client that will use these tokens to sign the
// requests it issues.
// BaseURL should refer to the root of the MAAS server path, e.g.
// http://my.maas.server.example.com/MAAS/
// apiVersion should contain the version of the MAAS API that you want to use.
func NewAuthenticatedClient(BaseURL string, apiKey string, apiVersion string) (*Client, error) {
// NewAuthenticatedClient parses the given MAAS API key into the
// individual OAuth tokens and creates an Client that will use these
// tokens to sign the requests it issues.
// versionedURL should be the location of the versioned API root of
// the MAAS server, e.g.:
// http://my.maas.server.example.com/MAAS/api/2.0/
func NewAuthenticatedClient(versionedURL, apiKey string) (*Client, error) {
elements := strings.Split(apiKey, ":")
if len(elements) != 3 {
errString := fmt.Sprintf("invalid API key %q; expected \"<consumer secret>:<token key>:<token secret>\"", apiKey)
Expand All @@ -306,9 +310,9 @@ func NewAuthenticatedClient(BaseURL string, apiKey string, apiVersion string) (*
if err != nil {
return nil, err
}
parsedBaseURL, err := composeAPIURL(BaseURL, apiVersion)
parsedURL, err := url.Parse(EnsureTrailingSlash(versionedURL))
if err != nil {
return nil, err
}
return &Client{Signer: signer, APIURL: parsedBaseURL}, nil
return &Client{Signer: signer, APIURL: parsedURL}, nil
}
16 changes: 7 additions & 9 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (suite *ClientSuite) TestClientdispatchRequestSignsRequest(c *gc.C) {
expectedResult := "expected:result"
server := newSingleServingServer(URI, expectedResult, http.StatusOK)
defer server.Close()
client, err := NewAuthenticatedClient(server.URL, "the:api:key", "1.0")
client, err := NewAuthenticatedClient(server.URL, "the:api:key")
c.Assert(err, jc.ErrorIsNil)
request, err := http.NewRequest("GET", server.URL+URI, nil)
c.Assert(err, jc.ErrorIsNil)
Expand Down Expand Up @@ -277,7 +277,7 @@ func (suite *ClientSuite) TestNewAnonymousClientEnsuresTrailingSlash(c *gc.C) {
}

func (suite *ClientSuite) TestNewAuthenticatedClientEnsuresTrailingSlash(c *gc.C) {
client, err := NewAuthenticatedClient("http://example.com/", "a:b:c", "1.0")
client, err := NewAuthenticatedClient("http://example.com/api/1.0", "a:b:c")
c.Assert(err, jc.ErrorIsNil)
expectedURL, err := url.Parse("http://example.com/api/1.0/")
c.Assert(err, jc.ErrorIsNil)
Expand All @@ -293,7 +293,7 @@ func (suite *ClientSuite) TestNewAuthenticatedClientParsesApiKey(c *gc.C) {
keyElements := []string{consumerKey, tokenKey, tokenSecret}
apiKey := strings.Join(keyElements, ":")

client, err := NewAuthenticatedClient("http://example.com/", apiKey, "1.0")
client, err := NewAuthenticatedClient("http://example.com/api/1.0/", apiKey)

c.Assert(err, jc.ErrorIsNil)
signer := client.Signer.(*plainTextOAuthSigner)
Expand All @@ -303,17 +303,15 @@ func (suite *ClientSuite) TestNewAuthenticatedClientParsesApiKey(c *gc.C) {
}

func (suite *ClientSuite) TestNewAuthenticatedClientFailsIfInvalidKey(c *gc.C) {
client, err := NewAuthenticatedClient("", "invalid-key", "1.0")
client, err := NewAuthenticatedClient("", "invalid-key")

c.Check(err, gc.ErrorMatches, "invalid API key.*")
c.Check(client, gc.IsNil)

}

func (suite *ClientSuite) TestcomposeAPIURLReturnsURL(c *gc.C) {
apiurl, err := composeAPIURL("http://example.com/MAAS", "1.0")
c.Assert(err, jc.ErrorIsNil)
expectedURL, err := url.Parse("http://example.com/MAAS/api/1.0/")
c.Assert(err, jc.ErrorIsNil)
func (suite *ClientSuite) TestAddAPIVersionToURL(c *gc.C) {
apiurl := AddAPIVersionToURL("http://example.com/MAAS", "1.0")
expectedURL := "http://example.com/MAAS/api/1.0/"
c.Assert(expectedURL, jc.DeepEquals, apiurl)
}
14 changes: 7 additions & 7 deletions controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func NewController(args ControllerArgs) (Controller, error) {
if err != nil {
return nil, errors.Errorf("bad version defined in supported versions: %q", apiVersion)
}
client, err := NewAuthenticatedClient(args.BaseURL, args.APIKey, apiVersion)
client, err := NewAuthenticatedClient(AddAPIVersionToURL(args.BaseURL, apiVersion), args.APIKey)
if err != nil {
// If the credentials aren't valid, return now.
if errors.IsNotValid(err) {
Expand All @@ -73,9 +73,9 @@ func NewController(args ControllerArgs) (Controller, error) {
Major: major,
Minor: minor,
}
controller := &controller{client: client}
controller := &controller{client: client, apiVersion: controllerVersion}
// The controllerVersion returned from the function will include any patch version.
controller.capabilities, controller.apiVersion, err = controller.readAPIVersion(controllerVersion)
controller.capabilities, err = controller.readAPIVersionInfo()
if err != nil {
logger.Debugf("read version failed: %#v", err)
continue
Expand Down Expand Up @@ -805,10 +805,10 @@ func nextRequestID() int64 {
return atomic.AddInt64(&requestNumber, 1)
}

func (c *controller) readAPIVersion(apiVersion version.Number) (set.Strings, version.Number, error) {
func (c *controller) readAPIVersionInfo() (set.Strings, error) {
parsed, err := c.get("version")
if err != nil {
return nil, apiVersion, errors.Trace(err)
return nil, errors.Trace(err)
}

// As we care about other fields, add them.
Expand All @@ -818,7 +818,7 @@ func (c *controller) readAPIVersion(apiVersion version.Number) (set.Strings, ver
checker := schema.FieldMap(fields, nil) // no defaults
coerced, err := checker.Coerce(parsed, nil)
if err != nil {
return nil, apiVersion, WrapWithDeserializationError(err, "version response")
return nil, WrapWithDeserializationError(err, "version response")
}
// For now, we don't append any subversion, but as it becomes used, we
// should parse and check.
Expand All @@ -832,7 +832,7 @@ func (c *controller) readAPIVersion(apiVersion version.Number) (set.Strings, ver
capabilities.Add(value.(string))
}

return capabilities, apiVersion, nil
return capabilities, nil
}

func parseAllocateConstraintsResponse(source interface{}, machine *machine) (ConstraintMatches, error) {
Expand Down
3 changes: 2 additions & 1 deletion example/live_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ func main() {
getParams()

// Create API server endpoint.
authClient, err := gomaasapi.NewAuthenticatedClient(apiURL, apiKey, apiVersion)
authClient, err := gomaasapi.NewAuthenticatedClient(
gomaasapi.AddAPIVersionToURL(apiURL, apiVersion), apiKey)
checkError(err)
maas := gomaasapi.NewMAAS(*authClient)

Expand Down

0 comments on commit 34256e9

Please sign in to comment.