Skip to content

Commit

Permalink
Merge pull request #14 from mgazz/events
Browse files Browse the repository at this point in the history
Add first EventListener implementation with the following features:
  • Loading branch information
mgazz committed May 24, 2023
2 parents 8409c18 + 1b73407 commit ad09f0a
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 8 deletions.
118 changes: 118 additions & 0 deletions api_emulator/redfish/EventListener_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from flask import request
from flask_restful import Resource
from .constants import *
import requests
import json

from api_emulator.utils import create_path, create_object

from api_emulator.redfish.Manager_api import ManagerCollectionAPI

import logging

config = {}

INTERNAL_ERROR = 500


# EventListener does not have a Collection API

class EventProcessor(Resource):
def __init__(self):
logging.info('Event Listener init called')
self.root = PATHS['Root']

def fetchResource(self, obj_id, obj_root, host, port):

resource_endpoint = f"{host}:{port}/{obj_id}"
logging.info(f"fetch: {resource_endpoint}")
response = requests.get(resource_endpoint)

if response.status_code == 200:
redfish_obj = response.json()

obj_path = "".join(redfish_obj['@odata.id'].split('/redfish/v1/'))
file_path = create_path(self.root, obj_path)
create_object(redfish_obj, [], [], file_path)

if 'Collection' in redfish_obj['@odata.type']:
logging.info(f"Found collection {redfish_obj['@odata.type']}")
EventProcessor.recursiveFetch(self, {'Members': redfish_obj['Members']}, obj_root, host, port)

def recursiveFetch(self, obj_dict, obj_root, host, port):
logging.info(f"dict: {obj_dict}, obj_root:{obj_root}")
if obj_root is None or not obj_root or type(obj_dict) is not dict:
return

for key, value in obj_dict.items():
logging.info(f"checking k:{key}, v:{value}")
if key == 'Links': # Do not explore Links for now
logging.info(f"returning k:{key}, v:{value}")
continue
elif key == '@odata.id' and obj_root in value and obj_root != value:
logging.info(f"fetch k:{key}, v:{value}")
EventProcessor.fetchResource(self, value, obj_root, host, port)

if type(value) == dict:
EventProcessor.recursiveFetch(self, value, obj_root, host, port)
elif type(value) == list:
for element in value:
EventProcessor.recursiveFetch(self, element, obj_root, host, port)

def ManagerCreated(self):
logging.info("ManagerCreated method called")
config = json.loads(request.data)
for event in config['Events']:
host = event['MessageArgs'][0]
port = event['MessageArgs'][1]
response = requests.get(f"{host}:{port}/{event['OriginOfCondition']['@odata.id']}")
if response.status_code == 200:
redfish_obj = response.json()

request.data = json.dumps(redfish_obj, indent=2).encode('utf-8')
# Update ManagerCollection before fetching the resource subtree
ManagerCollectionAPI.post(self)
EventProcessor.recursiveFetch(self, redfish_obj, redfish_obj['@odata.id'], host, port)


def handle_events(res):
config = json.loads(request.data)
for event in config['Events']:
###
# Each MessageId identifies the name of the handler that will be used to process the event
# For instance an event json with MessageId as following will be handled by the function ConnectionCreated
# {
# ...
# 'MessageId': 'Manager.1.0.ManagerCreated'
# ...
# }
###
handlerfunc = getattr(EventProcessor, event['MessageId'].split(".")[-1])
handlerfunc(res)


# EventListener API
class EventListenerAPI(Resource):
def __init__(self, **kwargs):
logging.info('Event Listener init called')
self.root = PATHS['Root']
self.auth = kwargs['auth']

# HTTP GET
def get(self):
logging.info('Event Listener get called')
return {}

# HTTP POST Collection
def post(self):
logging.info('Event Listener post called')
if request.data:
config = json.loads(request.data)
logging.info(f"Received request json: {config}")
handle_events(self)

return {}

# HTTP PUT Collection
def put(self):
logging.info('Event Listener put called')
3 changes: 3 additions & 0 deletions api_emulator/resource_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
from api_emulator.redfish.EthernetInterface5_api import *
from api_emulator.redfish.EthernetInterface6_api import *
from api_emulator.redfish.EventDestination_api import *
from api_emulator.redfish.EventListener_api import *
from api_emulator.redfish.ExternalAccountProvider0_api import *
from api_emulator.redfish.ExternalAccountProvider1_api import *
from api_emulator.redfish.FabricAdapter0_api import *
Expand Down Expand Up @@ -2225,6 +2226,8 @@ def __init__(self, rest_base, spec, mode, auth, trays=None):

g.api.add_resource(JobServiceAPI, '/redfish/v1/JobService', resource_class_kwargs={'auth': auth})

g.api.add_resource(EventListenerAPI, '/EventListener',resource_class_kwargs={'auth': auth})

g.api.add_resource(KeyServiceAPI, '/redfish/v1/KeyService', resource_class_kwargs={'auth': auth})

g.api.add_resource(LicenseServiceAPI, '/redfish/v1/LicenseService', resource_class_kwargs={'auth': auth})
Expand Down
23 changes: 15 additions & 8 deletions api_emulator/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,8 @@ def get_json_data(path):
# return jsonify(data)
return data

def create_object (config, members, member_ids, path):
# For POST Singleton API:
def create_and_patch_object (config, members, member_ids, path, collection_path):

# If input body data, then update properties
if request.data:
request_data = json.loads(request.data)
# Update the keys of payload in json file.
for key, value in request_data.items():
config[key] = value

members.append(config)
member_ids.append({'@odata.id': config['@odata.id']})
Expand All @@ -197,8 +190,22 @@ def create_and_patch_object (config, members, member_ids, path, collection_path)
with open(os.path.join(path, "index.json"), "w") as fd:
fd.write(json.dumps(config, indent=4, sort_keys=True))

def create_and_patch_object (config, members, member_ids, path, collection_path):

# If input body data, then update properties
if request.data:
request_data = json.loads(request.data)
# Update the keys of payload in json file.
for key, value in request_data.items():
config[key] = value

res = create_object(config,members,member_ids,path)
if res != None:
return res

# update the collection json file with new added resource
update_collections_json(path=collection_path, link=config['@odata.id'])

return config

def delete_object (path, base_path):
Expand Down

0 comments on commit ad09f0a

Please sign in to comment.