Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c24fe07

Browse files
authored
fix issue with blocking sockets in HTTP2 server; minor refactoring of /graph endpoint (#3091)
1 parent ac45c24 commit c24fe07

File tree

5 files changed

+96
-96
lines changed

5 files changed

+96
-96
lines changed

‎localstack/dashboard/api.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def spec():
2929

3030
@app.route('/graph', methods=['POST'])
3131
def get_graph():
32+
# TODO remove?
3233
""" Get deployment graph
3334
---
3435
operationId: 'getGraph'
@@ -38,7 +39,7 @@ def get_graph():
3839
"""
3940
data = get_payload()
4041
env = Environment.from_string(data.get('awsEnvironment'))
41-
graph = infra.get_graph(name_filter=data['nameFilter'], env=env)
42+
graph = infra.get_graph(name_filter=data['nameFilter'], env=env, region=data.get('awsRegion'))
4243
return jsonify(graph)
4344

4445

‎localstack/dashboard/infra.py

Lines changed: 77 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def get_kinesis_streams(filter='.*', pool={}, env=None):
121121
pool[arn] = stream
122122
stream.shards = get_kinesis_shards(stream_details=details, env=env)
123123
result.append(stream)
124-
except socket.error:
124+
except Exception:
125125
pass
126126
return result
127127

@@ -153,7 +153,7 @@ def get_sqs_queues(filter='.*', pool={}, env=None):
153153
if re.match(filter, name):
154154
queue = SqsQueue(arn)
155155
result.append(queue)
156-
except socket.error:
156+
except Exception:
157157
pass
158158
return result
159159

@@ -237,7 +237,7 @@ def handle(func):
237237
out = cmd_lambda('list-functions', env)
238238
out = json.loads(out)
239239
parallelize(handle, out['Functions'])
240-
except socket.error:
240+
except Exception:
241241
pass
242242
return result
243243

@@ -320,7 +320,7 @@ def handle(domain):
320320
result.append(es)
321321
pool[arn] = es
322322
parallelize(handle, out['DomainNames'])
323-
except socket.error:
323+
except Exception:
324324
pass
325325

326326
return result
@@ -344,7 +344,7 @@ def handle(table):
344344
result.append(db)
345345
pool[arn] = db
346346
parallelize(handle, out['TableNames'])
347-
except socket.error:
347+
except Exception:
348348
pass
349349
return result
350350

@@ -377,7 +377,7 @@ def handle(bucket):
377377
out = cmd_s3api('list-buckets', env)
378378
out = json.loads(out)
379379
parallelize(handle, out['Buckets'])
380-
except socket.error:
380+
except Exception:
381381
pass
382382
return result
383383

@@ -399,7 +399,7 @@ def get_firehose_streams(filter='.*', pool={}, env=None):
399399
bucket = EventSource.get(dest_s3, pool=pool)
400400
s.destinations.append(bucket)
401401
result.append(s)
402-
except socket.error:
402+
except Exception:
403403
pass
404404
return result
405405

@@ -413,87 +413,84 @@ def read_kinesis_iterator(shard_iterator, max_results=10, env=None):
413413

414414

415415
def get_kinesis_events(stream_name, shard_id, max_results=10, env=None):
416-
env = aws_stack.get_environment(env)
417-
records = aws_stack.kinesis_get_latest_records(stream_name, shard_id, count=max_results, env=env)
418-
for r in records:
419-
r['ApproximateArrivalTimestamp'] = mktime(r['ApproximateArrivalTimestamp'])
420-
result = {
421-
'events': records
422-
}
416+
records = []
417+
try:
418+
env = aws_stack.get_environment(env)
419+
records = aws_stack.kinesis_get_latest_records(stream_name, shard_id, count=max_results, env=env)
420+
for r in records:
421+
r['ApproximateArrivalTimestamp'] = mktime(r['ApproximateArrivalTimestamp'])
422+
except Exception:
423+
pass
424+
result = {'events': records}
423425
return result
424426

425427

426-
def get_graph(name_filter='.*', env=None):
428+
def get_graph(name_filter='.*', env=None, **kwargs):
427429
result = {
428430
'nodes': [],
429431
'edges': []
430432
}
431433

432434
pool = {}
433-
434-
if True:
435-
result = {
436-
'nodes': [],
437-
'edges': []
438-
}
439-
node_ids = {}
440-
# Make sure we load components in the right order:
441-
# (ES,DynamoDB,S3) -> (Kinesis,Lambda)
442-
domains = get_elasticsearch_domains(name_filter, pool=pool, env=env)
443-
dbs = get_dynamo_dbs(name_filter, pool=pool, env=env)
444-
buckets = get_s3_buckets(name_filter, details=True, pool=pool, env=env)
445-
streams = get_kinesis_streams(name_filter, pool=pool, env=env)
446-
firehoses = get_firehose_streams(name_filter, pool=pool, env=env)
447-
lambdas = get_lambda_functions(name_filter, details=True, pool=pool, env=env)
448-
queues = get_sqs_queues(name_filter, pool=pool, env=env)
449-
450-
for es in domains:
451-
uid = short_uid()
452-
node_ids[es.id] = uid
453-
result['nodes'].append({'id': uid, 'arn': es.id, 'name': es.name(), 'type': 'es'})
454-
for b in buckets:
455-
uid = short_uid()
456-
node_ids[b.id] = uid
457-
result['nodes'].append({'id': uid, 'arn': b.id, 'name': b.name(), 'type': 's3'})
458-
for db in dbs:
459-
uid = short_uid()
460-
node_ids[db.id] = uid
461-
result['nodes'].append({'id': uid, 'arn': db.id, 'name': db.name(), 'type': 'dynamodb'})
462-
for s in streams:
463-
uid = short_uid()
464-
node_ids[s.id] = uid
465-
result['nodes'].append({'id': uid, 'arn': s.id, 'name': s.name(), 'type': 'kinesis'})
466-
for shard in s.shards:
467-
uid1 = short_uid()
468-
name = re.sub(r'shardId-0*', '', shard.id) or '0'
469-
result['nodes'].append({'id': uid1, 'arn': shard.id, 'name': name,
470-
'type': 'kinesis_shard', 'streamName': s.name(), 'parent': uid})
471-
for f in firehoses:
472-
uid = short_uid()
473-
node_ids[f.id] = uid
474-
result['nodes'].append({'id': uid, 'arn': f.id, 'name': f.name(), 'type': 'firehose'})
475-
for d in f.destinations:
476-
result['edges'].append({'source': uid, 'target': node_ids[d.id]})
477-
for q in queues:
478-
uid = short_uid()
479-
node_ids[q.id] = uid
480-
result['nodes'].append({'id': uid, 'arn': q.id, 'name': q.name(), 'type': 'sqs'})
481-
for lda in lambdas:
482-
uid = short_uid()
483-
node_ids[lda.id] = uid
484-
result['nodes'].append({'id': uid, 'arn': lda.id, 'name': lda.name(), 'type': 'lambda'})
485-
for s in lda.event_sources:
486-
lookup_id = s.id
487-
if isinstance(s, DynamoDBStream):
488-
lookup_id = s.table.id
489-
result['edges'].append({'source': node_ids.get(lookup_id), 'target': uid})
490-
for t in lda.targets:
491-
lookup_id = t.id
492-
result['edges'].append({'source': uid, 'target': node_ids.get(lookup_id)})
493-
for b in buckets:
494-
for n in b.notifications:
495-
src_uid = node_ids[b.id]
496-
tgt_uid = node_ids[n.target.id]
497-
result['edges'].append({'source': src_uid, 'target': tgt_uid})
435+
node_ids = {}
436+
437+
# Make sure we load components in the right order:
438+
# (ES,DynamoDB,S3) -> (Kinesis,Lambda)
439+
domains = get_elasticsearch_domains(name_filter, pool=pool, env=env)
440+
dbs = get_dynamo_dbs(name_filter, pool=pool, env=env)
441+
buckets = get_s3_buckets(name_filter, details=True, pool=pool, env=env)
442+
streams = get_kinesis_streams(name_filter, pool=pool, env=env)
443+
firehoses = get_firehose_streams(name_filter, pool=pool, env=env)
444+
lambdas = get_lambda_functions(name_filter, details=True, pool=pool, env=env)
445+
queues = get_sqs_queues(name_filter, pool=pool, env=env)
446+
447+
for es in domains:
448+
uid = short_uid()
449+
node_ids[es.id] = uid
450+
result['nodes'].append({'id': uid, 'arn': es.id, 'name': es.name(), 'type': 'es'})
451+
for b in buckets:
452+
uid = short_uid()
453+
node_ids[b.id] = uid
454+
result['nodes'].append({'id': uid, 'arn': b.id, 'name': b.name(), 'type': 's3'})
455+
for db in dbs:
456+
uid = short_uid()
457+
node_ids[db.id] = uid
458+
result['nodes'].append({'id': uid, 'arn': db.id, 'name': db.name(), 'type': 'dynamodb'})
459+
for s in streams:
460+
uid = short_uid()
461+
node_ids[s.id] = uid
462+
result['nodes'].append({'id': uid, 'arn': s.id, 'name': s.name(), 'type': 'kinesis'})
463+
for shard in s.shards:
464+
uid1 = short_uid()
465+
name = re.sub(r'shardId-0*', '', shard.id) or '0'
466+
result['nodes'].append({'id': uid1, 'arn': shard.id, 'name': name,
467+
'type': 'kinesis_shard', 'streamName': s.name(), 'parent': uid})
468+
for f in firehoses:
469+
uid = short_uid()
470+
node_ids[f.id] = uid
471+
result['nodes'].append({'id': uid, 'arn': f.id, 'name': f.name(), 'type': 'firehose'})
472+
for d in f.destinations:
473+
result['edges'].append({'source': uid, 'target': node_ids[d.id]})
474+
for q in queues:
475+
uid = short_uid()
476+
node_ids[q.id] = uid
477+
result['nodes'].append({'id': uid, 'arn': q.id, 'name': q.name(), 'type': 'sqs'})
478+
for lda in lambdas:
479+
uid = short_uid()
480+
node_ids[lda.id] = uid
481+
result['nodes'].append({'id': uid, 'arn': lda.id, 'name': lda.name(), 'type': 'lambda'})
482+
for s in lda.event_sources:
483+
lookup_id = s.id
484+
if isinstance(s, DynamoDBStream):
485+
lookup_id = s.table.id
486+
result['edges'].append({'source': node_ids.get(lookup_id), 'target': uid})
487+
for t in lda.targets:
488+
lookup_id = t.id
489+
result['edges'].append({'source': uid, 'target': node_ids.get(lookup_id)})
490+
for b in buckets:
491+
for n in b.notifications:
492+
src_uid = node_ids[b.id]
493+
tgt_uid = node_ids[n.target.id]
494+
result['edges'].append({'source': src_uid, 'target': tgt_uid})
498495

499496
return result

‎localstack/services/edge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def serve_health_endpoint(method, path, data):
191191
def serve_resource_graph(data):
192192
data = json.loads(to_str(data or '{}'))
193193
env = Environment.from_string(data.get('awsEnvironment'))
194-
graph = dashboard_infra.get_graph(name_filter=data.get('nameFilter') or '.*', env=env)
194+
graph = dashboard_infra.get_graph(name_filter=data.get('nameFilter') or '.*', env=env, region=data.get('awsRegion'))
195195
return graph
196196

197197

‎localstack/services/generic_proxy.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818
from six.moves.urllib.parse import urlparse
1919
from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
2020
from localstack import config
21-
from localstack.config import USE_SSL, EXTRA_CORS_ALLOWED_HEADERS, EXTRA_CORS_EXPOSE_HEADERS
21+
from localstack.config import EXTRA_CORS_ALLOWED_HEADERS, EXTRA_CORS_EXPOSE_HEADERS
2222
from localstack.constants import APPLICATION_JSON
2323
from localstack.utils.server import http2_server
24-
from localstack.utils.common import FuncThread, generate_ssl_cert, to_bytes, json_safe, TMP_THREADS, path_from_url
24+
from localstack.utils.common import (
25+
FuncThread, generate_ssl_cert, to_bytes, json_safe, TMP_THREADS, path_from_url, Mock)
2526
from localstack.utils.testutil import is_local_test_mode
2627
from localstack.utils.http_utils import uses_chunked_encoding, create_chunked_data
2728
from localstack.utils.aws.aws_responses import LambdaResponse
@@ -446,9 +447,13 @@ def peek_ssl_header():
446447
return peek_ssl_header()
447448
except Exception:
448449
# Fix for "[Errno 11] Resource temporarily unavailable" - This can
449-
# happen if we're using a non-blocking socket in a blocking thread
450+
# happen if we're using a non-blocking socket in a blocking thread.
450451
newsock.setblocking(1)
451-
return peek_ssl_header()
452+
newsock.settimeout(1)
453+
try:
454+
return peek_ssl_header()
455+
except Exception:
456+
return False
452457

453458

454459
# set globally defined SSL socket implementation class
@@ -464,9 +469,10 @@ async def _accept_connection2(self, protocol_factory, conn, extra, sslcontext, *
464469

465470

466471
# patch asyncio server to accept SSL and non-SSL traffic over same port
467-
if hasattr(BaseSelectorEventLoop, '_accept_connection2'):
472+
if hasattr(BaseSelectorEventLoop, '_accept_connection2') and not hasattr(BaseSelectorEventLoop, '_ls_patched'):
468473
_accept_connection2_orig = BaseSelectorEventLoop._accept_connection2
469474
BaseSelectorEventLoop._accept_connection2 = _accept_connection2
475+
BaseSelectorEventLoop._ls_patched = True
470476

471477

472478
class GenericProxy(FuncThread):
@@ -514,7 +520,7 @@ def create_ssl_cert(cls, serial_number=None):
514520

515521
@classmethod
516522
def get_flask_ssl_context(cls, serial_number=None):
517-
if USE_SSL:
523+
if config.USE_SSL:
518524
_, cert_file_name, key_file_name = cls.create_ssl_cert(serial_number=serial_number)
519525
return (cert_file_name, key_file_name)
520526
return None
@@ -548,11 +554,8 @@ def handler(request, data):
548554
method = request.method
549555
headers = request.headers
550556

551-
class T:
552-
pass
553-
554-
request_handler = T()
555-
request_handler.proxy = T()
557+
request_handler = Mock()
558+
request_handler.proxy = Mock()
556559
request_handler.proxy.port = port
557560
response = modify_and_forward(method=method, path=path_with_params, data_bytes=data, headers=headers,
558561
forward_base_url=forward_url, listeners=[listener], request_handler=None,

‎requirements.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ boto>=2.49.0
1717
boto3>=1.14.33 #basic-lib
1818
botocore>=1.12.13
1919
cachetools>=3.1.1,<4.0.0
20+
cbor2>=5.2.0
2021
coverage==4.5.4
2122
crontab>=0.22.6
2223
dnspython==1.16.0 #basic-lib
@@ -28,6 +29,7 @@ flask>=1.0.2
2829
flask-cors>=3.0.3,<3.1.0
2930
flask_swagger==0.2.12
3031
forbiddenfruit==0.1.3
32+
jsondiff>=1.2.0
3133
jsonpatch>=1.24,<2.0
3234
jsonpath-rw>=1.4.0,<2.0.0
3335
localstack-ext[full]>=0.11.0
@@ -47,6 +49,3 @@ requests-aws4auth==0.9
4749
sasl>=0.2.1
4850
six>=1.12.0 #basic-lib
4951
xmltodict>=0.11.0
50-
cbor2>=5.2.0
51-
jsondiff>=1.2.0
52-
aws-xray-sdk>=2.6.0

0 commit comments

Comments
 (0)