예제 #1
0
async def process_task(task,
                       add_task) -> AsyncGenerator[Tuple[str, dict], None]:
    account_arn = f'arn:aws:iam::{task.account_id}:role/{AUDIT_READER_ROLE}'
    account_info = {'account_id': task.account_id}

    client_name, method_name = task.method.split('.', 1)

    try:
        session = _SESSION_CACHE[account_arn] = (
            _SESSION_CACHE[account_arn]
            if account_arn in _SESSION_CACHE else await aio_sts_assume_role(
                src_role_arn=AUDIT_ASSUMER_ARN,
                dest_role_arn=account_arn,
                dest_external_id=READER_EID,
            ))
        async with session.client(client_name) as client:
            if hasattr(client, 'describe_regions'):
                response = await client.describe_regions()
                region_names = [
                    region['RegionName'] for region in response['Regions']
                ]
            else:
                region_names = API_METHOD_SPECS[task.method].get(
                    'regions', [None])

        for rn in region_names:
            async with session.client(client_name, region_name=rn) as client:
                async for response in load_task_response(client, task):
                    if type(response) is DBEntry:
                        if rn is not None:
                            response.entity['region'] = rn
                        yield (task.method, response.entity)
                    elif type(response) is CollectTask:
                        add_task(response)
                    else:
                        log.info('log response', response)

    except ClientError as e:
        # record missing auditor role as empty account summary
        log.error(e, 'failed processing task')
        yield (
            task.method,
            updated(
                account_info,
                recorded_at=parse_date(
                    e.response['ResponseMetadata']['HTTPHeaders']['date']),
            ),
        )
예제 #2
0
async def fetch(session, url, fetch_over=0) -> dict:
    if fetch_over:
        await asyncio.sleep(fetch_over * random())
    async with session.get(f'https://snowflake.jamfcloud.com/JSSResource{url}',
                           headers=HEADERS) as response:
        txt = await response.text()
        date_header = response.headers.get('Date')
        if date_header is None:
            log.info(f'GET {url} -> status({response.status}) text({txt})')
            return {}

        result = {'recorded_at': parse_date(date_header)}
        try:
            return updated(result, json.loads(txt))
        except JSONDecodeError:
            log.info(f'GET {url} -> status({response.status}) text({txt})')
            return result
예제 #3
0
async def main(table_name):
    async with aiohttp.ClientSession() as session:
        cids = [
            c['id']
            for c in (await fetch(session, '/computers')).get('computers', [])
        ]

        log.info(f'loading {len(cids)} computer details')
        computers = await asyncio.gather(
            *[fetch_computer(session, cid) for cid in cids])

        log.info(f'inserting {len(computers)} computers into {table_name}')
        rows = [
            updated(c.get('computer'),
                    computer_id=cid,
                    recorded_at=c.get('recorded_at'))
            for cid, c in zip(cids, computers)
        ]
        db.insert(table_name, rows)
        return len(rows)
예제 #4
0
def process_aws_response(task, page):
    response_coldict = API_METHOD_SPECS[task.method]['response']
    children_list = API_METHOD_SPECS[task.method].get('children', [])
    params = API_METHOD_SPECS[task.method].get('params', {})

    base_entity = {}
    if task.account_id:
        base_entity['account_id'] = task.account_id

    base_entity.update({v: task.args[k] for k, v in params.items()})

    if isinstance(page, (Exception, type(None))):
        base_entity['recorded_at'] = datetime.now()
        yield DBEntry(base_entity)
        return

    metadata = page['ResponseMetadata']
    base_entity['recorded_at'] = parse_date(metadata['HTTPHeaders']['date'])
    if metadata['HTTPStatusCode'] != 200:
        yield DBEntry(base_entity)
        return

    base_entity.update(process_response_items(response_coldict, page))

    iterated_entries = list(process_response_lists(response_coldict, page))

    for entry in iterated_entries or [base_entity]:
        db_entry = DBEntry(updated(base_entity.copy(), entry))
        yield db_entry
        for child in children_list:
            for method in child.get('methods', [child.get('method')]):
                request_args = child.get('args', {})
                required_args = child.get('required_args', [])
                if any(v not in db_entry.entity
                       for v in request_args.values()):
                    continue
                if not all(db_entry.entity.get(k) for k in required_args):
                    continue
                args = {k: db_entry.entity[v] for k, v in request_args.items()}
                yield CollectTask(task.account_id, method, args)