Skip to content

Commit

Permalink
Support cert check, broken links, and step monitor migration (#52)
Browse files Browse the repository at this point in the history
* Support cert check monitor migration

* Support broken links monitor migration

* Support step monitor migration

* Fix simple browser monitor migration typo
  • Loading branch information
crshanks authored Dec 12, 2024
1 parent 555e831 commit aa93f2f
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 128 deletions.
2 changes: 2 additions & 0 deletions fetchmonitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def fetch_monitors(api_key, account_id, output_file, insights_key, region):
if monitortypes.is_scripted(monitor_json['definition']):
populate_secure_credentials(monitor_json, account_id, insights_key, region)
mc.MonitorsClient.populate_script(api_key, account_id, monitor_json, monitor_json['definition']['guid'], region)
if monitortypes.is_step_monitor(monitor_json['definition']):
mc.MonitorsClient.populate_steps(api_key, account_id, monitor_json, monitor_json['definition']['guid'], region)
store.save_monitor_to_file(monitor_name, storage_dir, monitor_json)
logger.info("Fetched %d monitors in %s", len(all_monitors_def_json), storage_dir)
return timestamp
Expand Down
207 changes: 104 additions & 103 deletions library/clients/monitorsclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import library.monitortypes as monitortypes
import library.status.monitorstatus as monitorstatus
import library.migrationlogger as nrlogger
import library.clients.entityclient as ec
import library.clients.gql as nerdgraph
import library.securecredentials as securecredentials
from library.clients.endpoints import Endpoints
import time

Expand Down Expand Up @@ -186,6 +188,25 @@ def query_script_gql(account_id, entity_guid):
return {'query': query, 'variables': variables}


@staticmethod
def query_steps_gql(account_id, entity_guid):
query = '''query ($accountId: Int!, $entityGuid: EntityGuid!) {
actor {
account(id: $accountId) {
synthetics {
steps(monitorGuid: $entityGuid) {
ordinal
type
values
}
}
}
}
}'''
variables = {'accountId': int(account_id), 'entityGuid': entity_guid}
return {'query': query, 'variables': variables}


@staticmethod
def fetch_script(api_key, account_id, monitor_name, entity_guid, region):
script_text = None
Expand Down Expand Up @@ -223,85 +244,56 @@ def populate_script(api_key, account_id, monitor_json, entity_guid, region):


@staticmethod
def create_simple_monitor_gql(account_id, monitor):
# Create syntheticsCreateSimpleMonitor
mutation = '''mutation ($accountId: Int!, $monitor: SyntheticsCreateSimpleMonitorInput!) {
syntheticsCreateSimpleMonitor(
accountId: $accountId
monitor: $monitor
) {
monitor {
guid
}
errors {
description
type
}
}
}'''
variables = {'accountId': int(account_id), 'monitor': monitor}
return {'query': mutation, 'variables': variables}


@staticmethod
def create_script_api_monitor_gql(account_id, monitor):
# Create syntheticsCreateScriptApiMonitor
mutation = '''mutation ($accountId: Int!, $monitor: SyntheticsCreateScriptApiMonitorInput!) {
syntheticsCreateScriptApiMonitor(
accountId: $accountId
monitor: $monitor
) {
monitor {
guid
}
errors {
description
type
}
}
}'''
variables = {'accountId': int(account_id), 'monitor': monitor}
return {'query': mutation, 'variables': variables}
def fetch_steps(api_key, account_id, monitor_name, entity_guid, region):
steps = None
try:
payload = MonitorsClient.query_steps_gql(account_id, entity_guid)
logger.debug(json.dumps(payload))
result = nerdgraph.GraphQl.post(api_key, payload, region)
logger.debug(json.dumps(result))
if ('error' in result):
logger.error(f'Could not fetch steps')
logger.error(result['error'])
else:
# No error attribute for steps
if 'response' in result:
logger.info("got steps for " + monitor_name)
steps = result['response']['data']['actor']['account']['synthetics']['steps']
else:
logger.error(f'Could not fetch steps')
logger.error(result)
except Exception as e:
logger.error(f'Error querying {monitor_name} steps for account {account_id} with entity_guid {entity_guid}')
logger.error(e)
logger.debug("Fetched steps : " + json.dumps(steps))
return steps


@staticmethod
def create_simple_browser_monitor_gql(account_id, monitor):
# Create syntheticsCreateSimpleBrowserMonitor
mutation = '''mutation ($accountId: Int!, $monitor: SyntheticsCreateSimpleBrowserMonitorInput!) {
syntheticsCreateSimpleBrowserMonitor(
accountId: $accountId
monitor: $monitor
) {
monitor {
guid
}
errors {
description
type
}
}
}'''
variables = {'accountId': int(account_id), 'monitor': monitor}
return {'query': mutation, 'variables': variables}
def populate_steps(api_key, account_id, monitor_json, entity_guid, region):
monitor_name = monitor_json['definition']['name']
logger.info(f'Querying {monitor_name} script for account {account_id}, with entity_guid {entity_guid}')
steps = MonitorsClient.fetch_steps(api_key, account_id, monitor_name, entity_guid, region)
monitor_json['steps'] = steps


@staticmethod
def create_script_browser_monitor_gql(account_id, monitor):
# Create syntheticsCreateScriptBrowserMonitor
mutation = '''mutation ($accountId: Int!, $monitor: SyntheticsCreateScriptBrowserMonitorInput!) {
syntheticsCreateScriptBrowserMonitor(
def create_monitor_gql(account_id, monitor, monitor_type, monitor_input_type):
# Create monitor
mutation = f'''mutation ($accountId: Int!, $monitor: {monitor_input_type}) {{
{monitor_type} (
accountId: $accountId
monitor: $monitor
) {
monitor {
) {{
monitor {{
guid
}
errors {
}}
errors {{
description
type
}
}
}'''
}}
}}
}}'''
variables = {'accountId': int(account_id), 'monitor': monitor}
return {'query': mutation, 'variables': variables}

Expand All @@ -313,14 +305,31 @@ def post_monitor_definition(api_key, monitor_name, monitor, monitor_status, tgt_
logger.debug(monitor_data)
payload = None
try:
monitor_type_function = None
if monitor['definition']['monitorType'] == 'SIMPLE':
payload = MonitorsClient.create_simple_monitor_gql(tgt_acct_id, monitor_data)
monitor_type_function = monitortypes.SIMPLE_FUNCTION
payload = MonitorsClient.create_monitor_gql(tgt_acct_id, monitor_data, monitor_type_function, monitortypes.SIMPLE_INPUT_TYPE)
elif monitor['definition']['monitorType'] == 'SCRIPT_API':
payload = MonitorsClient.create_script_api_monitor_gql(tgt_acct_id, monitor_data)
monitor_type_function = monitortypes.SCRIPT_API_FUNCTION
payload = MonitorsClient.create_monitor_gql(tgt_acct_id, monitor_data, monitor_type_function, monitortypes.SCRIPT_API_INPUT_TYPE)
elif monitor['definition']['monitorType'] == 'BROWSER':
payload = MonitorsClient.create_simple_browser_monitor_gql(tgt_acct_id, monitor_data)
monitor_type_function = monitortypes.SIMPLE_BROWSER_FUNCTION
payload = MonitorsClient.create_monitor_gql(tgt_acct_id, monitor_data, monitor_type_function, monitortypes.SIMPLE_BROWSER_INPUT_TYPE)
elif monitor['definition']['monitorType'] == 'SCRIPT_BROWSER':
payload = MonitorsClient.create_script_browser_monitor_gql(tgt_acct_id, monitor_data)
monitor_type_function = monitortypes.SCRIPT_BROWSER_FUNCTION
payload = MonitorsClient.create_monitor_gql(tgt_acct_id, monitor_data, monitor_type_function, monitortypes.SCRIPT_BROWSER_INPUT_TYPE)
elif monitor['definition']['monitorType'] == 'CERT_CHECK':
monitor_type_function = monitortypes.CERT_CHECK_FUNCTION
payload = MonitorsClient.create_monitor_gql(tgt_acct_id, monitor_data, monitor_type_function, monitortypes.CERT_CHECK_INPUT_TYPE)
elif monitor['definition']['monitorType'] == 'BROKEN_LINKS':
monitor_type_function = monitortypes.BROKEN_LINKS_FUNCTION
payload = MonitorsClient.create_monitor_gql(tgt_acct_id, monitor_data, monitor_type_function, monitortypes.BROKEN_LINKS_INPUT_TYPE)
elif monitor['definition']['monitorType'] == 'STEP_MONITOR':
monitor_type_function = monitortypes.STEP_MONITOR_FUNCTION
payload = MonitorsClient.create_monitor_gql(tgt_acct_id, monitor_data, monitor_type_function, monitortypes.STEP_MONITOR_INPUT_TYPE)
else:
logger.error(f'Unknown monitor type {monitor["definition"]["monitorType"]}')
return guid
logger.debug(json.dumps(payload))
result = nerdgraph.GraphQl.post(api_key, payload, region)
post_status = {monitorstatus.STATUS: result['status']}
Expand All @@ -330,34 +339,12 @@ def post_monitor_definition(api_key, monitor_name, monitor, monitor_status, tgt_
post_status[monitorstatus.ERROR] = result['error']
logger.error(f'Error creating monitor {monitor_name}')
logger.error(result['error'])
if monitor['definition']['monitorType'] == 'SIMPLE':
if result['response']['data']['syntheticsCreateSimpleMonitor']['errors']:
post_status[monitorstatus.ERROR] = result['response']['data']['syntheticsCreateSimpleMonitor']['errors']
logger.error(f'Could not create monitor {monitor_name}')
logger.error(result['response']['data']['syntheticsCreateSimpleMonitor']['errors'])
else:
guid = result['response']['data']['syntheticsCreateSimpleMonitor']['monitor']['guid']
elif monitor['definition']['monitorType'] == 'SCRIPT_API':
if result['response']['data']['syntheticsCreateScriptApiMonitor']['errors']:
post_status[monitorstatus.ERROR] = result['response']['data']['syntheticsCreateScriptApiMonitor']['errors']
logger.error(f'Could not create monitor {monitor_name}')
logger.error(result['response']['data']['syntheticsCreateScriptApiMonitor']['errors'])
else:
guid = result['response']['data']['syntheticsCreateScriptApiMonitor']['monitor']['guid']
elif monitor['definition']['monitorType'] == 'BROWSER':
if result['response']['data']['syntheticsCreateSimpleBrowserMonitor']['errors']:
post_status[monitorstatus.ERROR] = result['response']['data']['syntheticsCreateSimpleBrowserMonitor']['errors']
logger.error(f'Could not create monitor {monitor_name}')
logger.error(result['response']['data']['syntheticsCreateSimpleBrowserMonitor']['errors'])
else:
guid = result['response']['data']['syntheticsCreateSimpleBrowserMonitor']['monitor']['guid']
elif monitor['definition']['monitorType'] == 'SCRIPT_BROWSER':
if result['response']['data']['syntheticsCreateScriptBrowserMonitor']['errors']:
post_status[monitorstatus.ERROR] = result['response']['data']['syntheticsCreateScriptBrowserMonitor']['errors']
logger.error(f'Could not create monitor {monitor_name}')
logger.error(result['response']['data']['syntheticsCreateScriptBrowserMonitor']['errors'])
else:
guid = result['response']['data']['syntheticsCreateScriptBrowserMonitor']['monitor']['guid']
if result['response']['data'][monitor_type_function]['errors']:
post_status[monitorstatus.ERROR] = result['response']['data'][monitor_type_function]['errors']
logger.error(f'Could not create monitor {monitor_name}')
logger.error(result['response']['data'][monitor_type_function]['errors'])
else:
guid = result['response']['data'][monitor_type_function]['monitor']['guid']
except Exception as e:
logger.error(f'Error creating {monitor_name} script for account {tgt_acct_id}')
logger.error(e)
Expand All @@ -382,7 +369,7 @@ def fetch_secure_credentials(insights_query_key, account_id, scripted_monitors,


def populate_script(api_key, monitor_json, monitor_id):
script_response = fetch_script(api_key, monitor_id)
script_response = MonitorsClient.fetch_script(api_key, monitor_id)
monitor_name = monitor_json['definition']['name']
if script_response['status'] == 200:
logger.info("got script for " + monitor_name)
Expand All @@ -396,7 +383,7 @@ def put_script(api_key, monitor_json, monitor_name, monitor_status):
script_payload = json.dumps(monitor_json['script'])
if 'location' in monitor_status[monitor_name]:
script_url = monitor_status[monitor_name]['location'] + "/script"
script_response = requests.put(script_url, headers=setup_headers(api_key), data=script_payload)
script_response = requests.put(script_url, headers=MonitorsClient.setup_headers(api_key), data=script_payload)
monitor_status[monitor_name][monitorstatus.SCRIPT_STATUS] = script_response.status_code
monitor_status[monitor_name][monitorstatus.SCRIPT_MESSAGE] = script_response.text
else:
Expand All @@ -406,6 +393,20 @@ def put_script(api_key, monitor_json, monitor_name, monitor_status):
logger.info(monitor_status[monitor_name])


def put_steps(api_key, monitor_json, monitor_name, monitor_status):
steps_payload = json.dumps(monitor_json['steps'])
if 'location' in monitor_status[monitor_name]:
steps_url = monitor_status[monitor_name]['location'] + "/steps"
steps_response = requests.put(steps_url, headers=MonitorsClient.setup_headers(api_key), data=steps_payload)
monitor_status[monitor_name][monitorstatus.STEPS_STATUS] = steps_response.status_code
monitor_status[monitor_name][monitorstatus.STEPS_MESSAGE] = steps_response.text
else:
logger.warn("No location found in monitor_status. Most likely it did not get created")
monitor_status[monitor_name][monitorstatus.STEPS_STATUS] = -1
monitor_status[monitor_name][monitorstatus.STEPS_MESSAGE] = 'MonitorNotFound'
logger.info(monitor_status[monitor_name])


def get_target_monitor_guid(monitor_name, per_api_key, tgt_acct_id):
result = ec.gql_get_matching_entity_by_name(per_api_key, ec.SYNTH_MONITOR, monitor_name, tgt_acct_id)
monitor_guid = ''
Expand All @@ -422,7 +423,7 @@ def update(api_key, monitor_id, update_json, monitor_name, region=Endpoints.REGI
logger.info(update_payload)
put_monitor_url = Endpoints.of(region).MONITORS_URL + str(monitor_id)
result = {'entityUpdated': False}
response = requests.patch(put_monitor_url, headers=setup_headers(api_key), data=update_payload)
response = requests.patch(put_monitor_url, headers=MonitorsClient.setup_headers(api_key), data=update_payload)
result['status'] = response.status_code
# A successful request will return a 204 No Content response, with an empty body.
if response.status_code != 204:
Expand Down
9 changes: 9 additions & 0 deletions library/localstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,15 @@ def load_script(monitor_dir, monitor):
logger.error("Script file does not exist " + script_file.name)


def load_steps(monitor_dir, monitor):
if monitortypes.is_step_monitor(monitor):
steps_file = monitor_dir / "steps.json"
if steps_file.exists():
monitor['steps'] = json.loads(steps_file.read_text())
else:
logger.error("Steps file does not exist " + steps_file.name)


def load_monitors(account_id, timestamp, monitor_names):
monitors = []
db_dir = Path(DB_DIR)
Expand Down
Loading

0 comments on commit aa93f2f

Please sign in to comment.