Merge pull request #1342 from ogayot/u-a-c-distinguish-error-invalid
ubuntu-advantage: determine on error if token was invalid
This commit is contained in:
commit
746e559c47
|
@ -13,7 +13,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from subprocess import CalledProcessError, CompletedProcess
|
from subprocess import CompletedProcess
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch, AsyncMock
|
from unittest.mock import patch, AsyncMock
|
||||||
|
|
||||||
|
@ -87,9 +87,9 @@ class TestUAClientUAInterfaceStrategy(unittest.IsolatedAsyncioTestCase):
|
||||||
mock_arun.return_value = CompletedProcess([], 0)
|
mock_arun.return_value = CompletedProcess([], 0)
|
||||||
mock_arun.return_value.stdout = "{}"
|
mock_arun.return_value.stdout = "{}"
|
||||||
await strategy.query_info(token="123456789")
|
await strategy.query_info(token="123456789")
|
||||||
mock_arun.assert_called_once_with(command, check=True)
|
mock_arun.assert_called_once_with(command, check=False)
|
||||||
|
|
||||||
async def test_query_info_failed(self):
|
async def test_query_info_unknown_error(self):
|
||||||
strategy = UAClientUAInterfaceStrategy()
|
strategy = UAClientUAInterfaceStrategy()
|
||||||
command = (
|
command = (
|
||||||
"ubuntu-advantage",
|
"ubuntu-advantage",
|
||||||
|
@ -99,12 +99,42 @@ class TestUAClientUAInterfaceStrategy(unittest.IsolatedAsyncioTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch(self.arun_command_sym) as mock_arun:
|
with patch(self.arun_command_sym) as mock_arun:
|
||||||
mock_arun.side_effect = CalledProcessError(returncode=1,
|
mock_arun.return_value.returncode = 2
|
||||||
cmd=command)
|
|
||||||
mock_arun.return_value.stdout = "{}"
|
mock_arun.return_value.stdout = "{}"
|
||||||
with self.assertRaises(CheckSubscriptionError):
|
with self.assertRaises(CheckSubscriptionError):
|
||||||
await strategy.query_info(token="123456789")
|
await strategy.query_info(token="123456789")
|
||||||
mock_arun.assert_called_once_with(command, check=True)
|
mock_arun.assert_called_once_with(command, check=False)
|
||||||
|
|
||||||
|
async def test_query_info_invalid_token(self):
|
||||||
|
strategy = UAClientUAInterfaceStrategy()
|
||||||
|
command = (
|
||||||
|
"ubuntu-advantage",
|
||||||
|
"status",
|
||||||
|
"--format", "json",
|
||||||
|
"--simulate-with-token", "123456789",
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(self.arun_command_sym) as mock_arun:
|
||||||
|
mock_arun.return_value.returncode = 1
|
||||||
|
mock_arun.return_value.stdout = """\
|
||||||
|
{
|
||||||
|
"environment_vars": [],
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"message": "Invalid token. See https://ubuntu.com/advantage",
|
||||||
|
"message_code": "attach-invalid-token",
|
||||||
|
"service": null,
|
||||||
|
"type": "system"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"result": "failure",
|
||||||
|
"services": [],
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
with self.assertRaises(InvalidTokenError):
|
||||||
|
await strategy.query_info(token="123456789")
|
||||||
|
mock_arun.assert_called_once_with(command, check=False)
|
||||||
|
|
||||||
async def test_query_info_invalid_json(self):
|
async def test_query_info_invalid_json(self):
|
||||||
strategy = UAClientUAInterfaceStrategy()
|
strategy = UAClientUAInterfaceStrategy()
|
||||||
|
@ -120,7 +150,7 @@ class TestUAClientUAInterfaceStrategy(unittest.IsolatedAsyncioTestCase):
|
||||||
mock_arun.return_value.stdout = "invalid-json"
|
mock_arun.return_value.stdout = "invalid-json"
|
||||||
with self.assertRaises(CheckSubscriptionError):
|
with self.assertRaises(CheckSubscriptionError):
|
||||||
await strategy.query_info(token="123456789")
|
await strategy.query_info(token="123456789")
|
||||||
mock_arun.assert_called_once_with(command, check=True)
|
mock_arun.assert_called_once_with(command, check=False)
|
||||||
|
|
||||||
|
|
||||||
class TestUAInterface(unittest.IsolatedAsyncioTestCase):
|
class TestUAInterface(unittest.IsolatedAsyncioTestCase):
|
||||||
|
|
|
@ -17,9 +17,10 @@ helper. """
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from datetime import datetime as dt
|
from datetime import datetime as dt
|
||||||
|
import contextlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from subprocess import CalledProcessError, CompletedProcess
|
from subprocess import CompletedProcess
|
||||||
from typing import List, Sequence, Union
|
from typing import List, Sequence, Union
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
@ -132,20 +133,36 @@ class UAClientUAInterfaceStrategy(UAInterfaceStrategy):
|
||||||
"--format", "json",
|
"--format", "json",
|
||||||
"--simulate-with-token", token,
|
"--simulate-with-token", token,
|
||||||
)
|
)
|
||||||
try:
|
|
||||||
proc: CompletedProcess = await utils.arun_command(command,
|
# On error, the command will exit with status 1. When that happens, the
|
||||||
check=True)
|
# output should still be formatted as a JSON object and we can inspect
|
||||||
|
# it to know the reason of the failure. This is how we figure out if
|
||||||
|
# the contract token was invalid.
|
||||||
|
proc: CompletedProcess = await utils.arun_command(command, check=False)
|
||||||
|
if proc.returncode == 0:
|
||||||
# TODO check if we're not returning a string or a list
|
# TODO check if we're not returning a string or a list
|
||||||
return json.loads(proc.stdout)
|
try:
|
||||||
except CalledProcessError:
|
return json.loads(proc.stdout)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
log.exception("Failed to parse output of command %r", command)
|
||||||
|
elif proc.returncode == 1:
|
||||||
|
try:
|
||||||
|
data = json.loads(proc.stdout)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
log.exception("Failed to parse output of command %r", command)
|
||||||
|
else:
|
||||||
|
token_invalid = False
|
||||||
|
with contextlib.suppress(KeyError):
|
||||||
|
for error in data["errors"]:
|
||||||
|
if error["message_code"] == "attach-invalid-token":
|
||||||
|
token_invalid = True
|
||||||
|
log.debug("error reported by u-a-c: %s: %s",
|
||||||
|
error["message_code"], error["message"])
|
||||||
|
if token_invalid:
|
||||||
|
raise InvalidTokenError(token)
|
||||||
|
|
||||||
|
else:
|
||||||
log.exception("Failed to execute command %r", command)
|
log.exception("Failed to execute command %r", command)
|
||||||
# TODO Check if the command failed because the token is invalid.
|
|
||||||
# Currently, ubuntu-advantage fails with the following error when
|
|
||||||
# the token is invalid:
|
|
||||||
# * Failed to connect to authentication server
|
|
||||||
# * Check your Internet connection and try again.
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
log.exception("Failed to parse output of command %r", command)
|
|
||||||
|
|
||||||
message = "Unable to retrieve subscription information."
|
message = "Unable to retrieve subscription information."
|
||||||
raise CheckSubscriptionError(token, message=message)
|
raise CheckSubscriptionError(token, message=message)
|
||||||
|
|
Loading…
Reference in New Issue