Skip to content

Commit f993ac4

Browse files
committed
Fail gracefully when no region is configured
If we can't create a client for server side completion, we should not propogate an exception. Instead we should return no server side completion values. In the future, it would be nice to have some sort of notification area in the shell where we could let the user know that server side completion won't work because they don't have a region configured. Fixes awslabs#84.
1 parent bdc703a commit f993ac4

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed

awsshell/resource/index.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import jmespath
2222
from botocore import xform_name
23+
from botocore.exceptions import BotoCoreError
2324

2425
LOG = logging.getLogger(__name__)
2526

@@ -221,11 +222,21 @@ def retrieve_candidate_values(self, service, operation, param):
221222
# param='InstanceIds'.
222223
if service not in self._describer_creator.services_with_completions():
223224
return []
224-
client = self._client_creator.create_client(service)
225+
try:
226+
client = self._client_creator.create_client(service)
227+
except BotoCoreError as e:
228+
# create_client() could raise an exception if the session
229+
# isn't fully configured (say it's missing a region).
230+
# However, we don't want to turn off all server side
231+
# completions because it's still possible to create
232+
# clients for some services without a region, e.g. IAM.
233+
LOG.debug("Error when trying to create a client for %s",
234+
service, exc_info=True)
235+
return []
225236
api_operation_name = client.meta.method_to_api_mapping.get(
226237
operation.replace('-', '_'))
227238
if api_operation_name is None:
228-
return
239+
return []
229240
# Now we need to convert the param name to the
230241
# casing used by the API.
231242
completer = self._describer_creator.create_completer_query(service)
@@ -235,7 +246,9 @@ def retrieve_candidate_values(self, service, operation, param):
235246
return
236247
try:
237248
response = getattr(client, xform_name(result.operation, '_'))()
238-
except Exception:
249+
except Exception as e:
250+
LOG.debug("Error when calling %s.%s: %s", service,
251+
result.operation, e, exc_info=True)
239252
return
240253
results = jmespath.search(result.path, response)
241254
return results

tests/unit/test_resources.py

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
11
"""Index and retrive information from the resource JSON."""
22
import pytest
3+
import mock
4+
5+
from botocore.exceptions import NoRegionError
6+
37
from awsshell.resource import index
48

59

10+
@pytest.fixture
11+
def describer_creator():
12+
class FakeDescriberCreator(object):
13+
SERVICES = ['ec2']
14+
15+
def services_with_completions(self):
16+
return self.SERVICES
17+
18+
return FakeDescriberCreator()
19+
20+
621
def test_build_from_has_many():
722
resource = {
823
'service': {
@@ -211,14 +226,42 @@ def services_with_completions(self):
211226
assert factory.create_completer_query('ec2') == result
212227

213228

214-
def test_empty_results_returned_when_no_completion_data_exists():
215-
class FakeDescriberCreator(object):
216-
def services_with_completions(self):
217-
return []
229+
def test_empty_results_returned_when_no_completion_data_exists(describer_creator):
230+
describer_creator.SERVICES = []
218231

219232
completer = index.ServerSideCompleter(
220233
client_creator=None,
221-
describer_creator=FakeDescriberCreator()
234+
describer_creator=describer_creator,
222235
)
223236
assert completer.retrieve_candidate_values(
224237
'ec2', 'run-instances', 'ImageId') == []
238+
239+
240+
def test_no_completions_when_cant_create_client(describer_creator):
241+
client_creator = mock.Mock(spec=index.CachedClientCreator)
242+
# This is raised when you don't have a region configured via config file
243+
# env var or manually via a session.
244+
client_creator.create_client.side_effect = NoRegionError()
245+
completer = index.ServerSideCompleter(
246+
client_creator=client_creator,
247+
describer_creator=describer_creator)
248+
249+
assert completer.retrieve_candidate_values(
250+
'ec2', 'foo', 'Bar') == []
251+
252+
253+
def test_no_completions_returned_on_unknown_operation(describer_creator):
254+
client = mock.Mock()
255+
client_creator = mock.Mock(spec=index.CachedClientCreator)
256+
client_creator.create_client.return_value = client
257+
258+
client.meta.method_to_api_mapping = {
259+
'describe_foo': 'DescribeFoo'
260+
}
261+
262+
completer = index.ServerSideCompleter(
263+
client_creator=client_creator,
264+
describer_creator=describer_creator)
265+
266+
assert completer.retrieve_candidate_values(
267+
'ec2', 'not_describe_foo', 'Bar') == []

0 commit comments

Comments
 (0)