launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #13124
[Merge] lp:~allenap/maas/infer-api-uri into lp:maas
Gavin Panella has proposed merging lp:~allenap/maas/infer-api-uri into lp:maas.
Commit message:
Infer the API version, and thus URL, at the command-line.
Previously it was necessary to specify the full URL to the API root, e.g. http://example.com/api/1.0.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1061731 in MAAS: "MAAS does not infer the API url when one connects to the MAAS url using the cli."
https://bugs.launchpad.net/maas/+bug/1061731
For more details, see:
https://code.launchpad.net/~allenap/maas/infer-api-uri/+merge/128496
--
https://code.launchpad.net/~allenap/maas/infer-api-uri/+merge/128496
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/maas/infer-api-uri into lp:maas.
=== modified file 'src/maascli/cli.py'
--- src/maascli/cli.py 2012-10-08 10:27:52 +0000
+++ src/maascli/cli.py 2012-10-08 13:45:31 +0000
@@ -20,7 +20,7 @@
from maascli.command import Command
from maascli.config import ProfileConfig
from maascli.utils import (
- ensure_trailing_slash,
+ api_url,
parse_docstring,
safe_name,
)
@@ -41,9 +41,10 @@
"server and credentials within this tool."
))
parser.add_argument(
- "url", help=(
- "The URL of the remote API, e.g. "
- "http://example.com/MAAS/api/1.0/"))
+ "url", type=api_url, help=(
+ "The URL of the remote API, e.g. http://example.com/MAAS/ "
+ "or http://example.com/MAAS/api/1.0/ if you wish to specify "
+ "the API version."))
parser.add_argument(
"credentials", nargs="?", default=None, help=(
"The credentials, also known as the API key, for the "
@@ -61,11 +62,8 @@
# Try and obtain credentials interactively if they're not given, or
# read them from stdin if they're specified as "-".
credentials = obtain_credentials(options.credentials)
- # Normalise the remote service's URL.
- url = ensure_trailing_slash(options.url)
# Get description of remote API.
- insecure = options.insecure
- description = fetch_api_description(url, insecure)
+ description = fetch_api_description(options.url, options.insecure)
# Save the config.
profile_name = options.profile_name
with ProfileConfig.open() as config:
@@ -73,7 +71,7 @@
"credentials": credentials,
"description": description,
"name": profile_name,
- "url": url,
+ "url": options.url,
}
=== modified file 'src/maascli/tests/test_utils.py'
--- src/maascli/tests/test_utils.py 2012-10-07 22:06:22 +0000
+++ src/maascli/tests/test_utils.py 2012-10-08 13:45:31 +0000
@@ -18,9 +18,11 @@
from maascli import utils
from maastesting.testcase import TestCase
from testtools.matchers import (
+ AfterPreprocessing,
Equals,
IsInstance,
MatchesAll,
+ MatchesListwise,
)
@@ -194,3 +196,23 @@
name, value = unquote(name), unquote(value)
name, value = smart_unicode(name), smart_unicode(value)
self.assertEqual(data, [(name, value)])
+
+ def test_api_url(self):
+ transformations = {
+ "http://example.com/":
+ "http://example.com/api/1.0/",
+ "http://example.com/foo":
+ "http://example.com/foo/api/1.0/",
+ "http://example.com/foo/":
+ "http://example.com/foo/api/1.0/",
+ "http://example.com/api/7.9":
+ "http://example.com/api/7.9/",
+ "http://example.com/api/7.9/":
+ "http://example.com/api/7.9/",
+ }.items()
+ urls = [url for url, url_out in transformations]
+ expected = [
+ AfterPreprocessing(utils.api_url, Equals(url_out))
+ for url, url_out in transformations
+ ]
+ self.assertThat(urls, MatchesListwise(expected))
=== modified file 'src/maascli/utils.py'
--- src/maascli/utils.py 2012-10-07 22:06:22 +0000
+++ src/maascli/utils.py 2012-10-08 13:45:31 +0000
@@ -25,6 +25,7 @@
)
import re
from urllib import quote_plus
+from urlparse import urlparse
re_paragraph_splitter = re.compile(
@@ -85,6 +86,22 @@
return (string + slash) if not string.endswith(slash) else string
+def api_url(string):
+ """Ensure that `string` looks like a URL to the API.
+
+ This ensures that the API version is specified explicitly (i.e. the path
+ ends with /api/{version}). If not, version 1.0 is selected. It also
+ ensures that the path ends with a forward-slash.
+
+ This is suitable for use as an argument type with argparse.
+ """
+ url = urlparse(string)
+ url = url._replace(path=ensure_trailing_slash(url.path))
+ if re.search("/api/[0-9.]+/?$", url.path) is None:
+ url = url._replace(path=url.path + "api/1.0/")
+ return url.geturl()
+
+
def urlencode(data):
"""A version of `urllib.urlencode` that isn't insane.