Chapter 15. Event Processing

One of the most powerful features of CloudForms Automate is its capability to process events. CloudForms can monitor and respond to external (provider) events, such as a virtual machine starting or stopping, or a hypervisor going into maintenance. These events can then be used as triggers for Automate operations. We might wish to initiate a SmartState Analysis scan on a new VMware virtual machine when a VmCreatedEvent event is detected, for example. Perhaps we’d like to intercept and cancel a USER_INITIATED_SHUTDOWN_VM event being detected on a critical Red Hat Enterprise Virtualization (RHEV) virtual machine that we’ve tagged as do_not_shutdown.

CloudForms Automate also raises its own events internally, which can then be used as workflow triggers. We see an example of this when we provision a new virtual machine (we cover VM provisioning in Part II of the book). The workflow for provisioning a virtual machine includes an approval stage—we can optionally allow administrators to approve large VM requests—followed by a quota-checking stage to ensure that users are not exceeding their quota. The successful approval of the VM provisioning request results in Automate raising a request_approved internal event. This request_approved event is then used as the trigger to automatically start the quota-checking workflow (see Chapter 19 for more details on this workflow).

In this chapter we’ll examine in detail how events are processed by the Automation Engine. This is a deep-dive chapter containing useful background information but can be skipped for now if required. Event handling happens automatically in CloudForms, and an understanding of the event processing workflow can help us as we advance our Automate skills. In Chapter 43 we create an entirely new approval workflow, based largely on our knowledge of event processing.

To improve the scalability of event handling, particularly with the advent of new providers and provider types, the event processing mechanism has been substantially re-written in CloudForms 4.0. We’ll first look at the new component parts of Automate’s event processing, and then we’ll study how external events are caught and internal events are raised and handled.

Event Processing Component Parts

The are several new components involved in processing events in CloudForms 4.0, including an event stream object type, the Event Switchboard, and event handlers.

The Event Stream Object

Events are now handled by an EventStream object, derived from a parent EventStream class. An EventStream object is created in response to an external or internal event, and this object is sent to Automate to initiate the event handling process.

Events enter Automate at the /System/Process/Event instance, and this contains a rel5 relationship that redirects the handling of the event into the Event Switchboard. The root of the Event Switchboard is at /System/Event (see Figure 15-1).

mcla 1501
Figure 15-1. Entry relationship into the Event Switchboard

The Event Switchboard

The Event Switchboard is a new set of namespaces, classes, instances, and methods, written to handle the processing of events in a scalable manner.

/System/Process/Event contains a rel5 relationship into the switchboard, and this relationship URI comprises three parts: the event namespace, the event source, and the event type. Each is selected from the substitution of a runtime variable:

/System/Event/${/#event_stream.event_namespace} /
${/#event_stream.source} /
${/#event_type}

The substituted values are taken from attributes of the EventStream object representing the event and the event type.

Event stream namespace

The ${/#event_stream.event_namespace} part of the relationship translates to one of three event stream namespaces:

  • EmsEvent if the event’s origin was an external management system (i.e., a provider). An EmsEvent instance contains all information about its virtual machine, host, and provider related to the event.

  • MiqEvent if the event’s origin was an internal CloudForms/ManageIQ-initiated policy event.

  • RequestEvent if the event is related to an automation request (e.g., request_created).

These can be seen in Figure 15-2.

mcla 1502
Figure 15-2. Event stream namespaces

Event stream source

Within each of the event stream namespaces are classes that define the event stream source instances. The selection of source class is made from the substitution of the ${/#event_stream.source} part of the /System/Process/Event rel5 relationship. We can see that for the EmsEvent namespace, these represent the various external management systems (Amazon, OpenStack, etc.). See Figure 15-3.

mcla 1503
Figure 15-3. Event stream sources

Event type

Under the appropriate event stream source classes are instances that define the processing required for each event type. The selection of event type is made from the substitution of the ${/#event_type} part of the /System/Process/Event rel5 relationship. We can see that these represent the various events that the EventCatcher::Runner workers detect from the provider message bus. Figure 15-4 shows the event types in the Amazon namespace.

Event Types for the Amazon Event Stream Source
Figure 15-4. Event types for the Amazon event stream source

The event type instances contain one or more relationships to event handlers in the /System/event_handlers namespace that define the actions to take for that event. For example, the Amazon event AWS_EC2_Instance_running will call the event_action_policy handler to push a new vm_start policy event through the Switchboard. It also calls the event_action_refresh handler to trigger a provider refresh so that the current instance details can be retrieved (see Figure 15-5).

mcla 1505
Figure 15-5. The actions defined by the event type instance

Event Handlers

Event handlers are instances and methods that perform the actual granular processing for each event. The methods are built in for execution efficiency; their code is not visible in the Automate Explorer (see Figure 15-6).

mcla 1506
Figure 15-6. Event handler instances

Catching and Handling External Events

One of the CloudForms server roles that can be configured is Event Monitor. If we enable this role, we get two additional types of worker threads started on our appliance, to detect (catch) and process (handle) external provider events.

Event Catching

External (provider) events are monitored by EventCatcher workers, and these monitor the real-time message or event buses on the various providers: AWS:config for Amazon, AMQP/RabbitMQ for OpenStack, the native VMware message bus, or the RHEV-M events exposed through the RESTful API, for example.

There is a specific EventCatcher worker for each provider configured on an appliance. The EventCatcher workers are named in accordance with the new CloudForms 4.0 provider namespace format, so entries in evm.log appear as:

ManageIQ::Providers::Redhat::InfraManager::EventCatcher::Runner#process_event) 
      EMS [rhevm01] as [admin@internal] Caught event [USER_INITIATED_SHUTDOWN_VM]
ManageIQ::Providers::Redhat::InfraManager::EventCatcher::Runner#process_event) 
      EMS [rhevm01] as [admin@internal] Caught event [VM_DOWN]
...IQ::Providers::Openstack::CloudManager::EventCatcher::Runner#process_event) 
      EMS [rhosp-cont] as [admin] Caught event [compute.instance.power_on.start]

Event Processing

The EventCatcher workers queue the handling and processing of the specific event to one or more EventHandler workers. The arguments passed to the EventHandler include the provider-specific details for the event source.

We can trace the steps in the event processing workflow on an RHEV USER_RUN_VM event being caught.

Step 1

The first thing that we see in evm.log is the call to the EventHandler, along with arguments containing the RHEV API ids and hrefs describing the event source:

Args: [{:id=>"26790", 
    :href=>"/api/events/26790", 
    :cluster=>{
        :id=>"00000001-0001-0001-0001-000000000249", 
        :href=>"/api/clusters/00000001-0001-0001-0001-000000000249"}, 
    :data_center=>{
        :id=>"00000002-0002-0002-0002-000000000314",
        :href=>"/api/datacenters/00000002-0002-0002-0002-000000000314"}, 
    :host=>{
        :id=>"b959325b-c667-4e3a-a52e-fd936c225a1a", 
        :href=>"/api/hosts/b959325b-c667-4e3a-a52e-fd936c225a1a"}, 
    :user=>{
        :id=>"fdfc627c-d875-11e0-90f0-83df133b58cc", 
         :href=>"/api/users/fdfc627c-d875-11e0-90f0-83df133b58cc"}, 
    :vm=>{
        :id=>"4e7b66b7-080d-4593-b670-3d6259e47a0f", 
        :href=>"/api/vms/4e7b66b7-080d-4593-b670-3d6259e47a0f"}, 
    :description=>"VM rhel7srv010 started on Host rhelh03.bit63.net", 
    :severity=>"normal", 
    :code=>32, 
    :time=>2016-01-31 15:53:29 UTC, 
    :name=>"USER_RUN_VM"}]

Step 2

The EventHandler worker feeds the event into the Event Switchboard by creating and passing an EmsEvent EventStream object into Automate in the form of a queued request (we discuss queued requests more in Chapter 45). The EventHandlers translate the provider-specific arguments (API hrefs) into CloudForms object IDs and include these as arguments to the Automate request:

Args: [{:object_type=>"EmsEvent", 
        :object_id=>1000000007999, 
        :attrs=>{:event_id=>1000000007999, 
                 :event_stream_id=>1000000007999, 
                 :event_type=>"USER_RUN_VM", 
                 "VmOrTemplate::vm"=>1000000000023, 
                 :vm_id=>1000000000023, 
                 "Host::host"=>1000000000002, 
                 :host_id=>1000000000002}, 
                 :instance_name=>"Event", 
                 :user_id=>1000000000001, 
                 :miq_group_id=>1000000000002, 
                 :tenant_id=>1000000000001, 
                 :automate_message=>nil}]

Step 3

The request is dequeued and passed to the Automation Engine, which instantiates the /System/Process/Event entry point to the Event Switchboard, along with the arguments passed by the EventHandler:

<AutomationEngine> Instantiating [/System/Process/Event?
                   EventStream%3A%3Aevent_stream=1000000007999& 
                   Host%3A%3Ahost=1000000000002& 
                   MiqServer%3A%3Amiq_server=1000000000001& 
                   User%3A%3Auser=1000000000001& 
                   VmOrTemplate%3A%3Avm=1000000000023& 
                   event_id=1000000007999& 
                   event_stream_id=1000000007999& 
                   event_type=USER_RUN_VM& 
                   host_id=1000000000002& 
                   object_name=Event& 
                   vm_id=1000000000023& 
                   vmdb_object_type=event_stream]

Step 4

In the case of our RHEV USER_RUN_VM event, the Event Switchboard directs the processing to the /System/Event/EmsEvent/RHEVM/USER_RUN_VM instance, which contains relationships to two Automation event_handler instances (see Figure 15-7).

mcla 1507
Figure 15-7. Relationships to event_handler instances

Step 5

The rel4 relationship of the /System/Event/EmsEvent/RHEVM/USER_RUN_VM instance calls /System/event_handlers/event_action_policy to initiate the creation of an internal generic vm_start event.

This completes the event processing workflow for the external USER_RUN_VM event.

Creating and Processing Internal Events

In addition to catching external events, CloudForms can raise its own events that can be processed by control policies or alerts. These are generated and handled by two internal (non-Automate) methods, build_evm_event and process_evm_event.

We saw in “Step 5” that the rel4 relationship of the /System/Event/EmsEvent/RHEVM/USER_RUN_VM instance initiates the creation of a generic vm_start event. We find that most of the provider-specific events (such as USER_RUN_VM for RHEV or AWS_EC2_Instance_running for Amazon) are reraised as their generic equivalent event (such as vm_start).

We can continue following the processing of the USER_RUN_VM into the internal vm_start event by examining evm.log.

Step 6

We see the /System/event_handlers/event_action_policy event handler being invoked as requested in “Step 5”:

Invoking [builtin] method [/ManageIQ/System/event_handlers/event_action_policy] 
      with inputs [{"target"=>"src_vm", "policy_event"=>"vm_start", "param"=>""}]

This event handler calls the internal build_evm_event method to assemble the parameters for the creation of the new vm_start event:

<AutomationEngine> MiqAeEvent.build_evm_event >> event=<"vm_start">
    inputs=<{:"manageiq::providers::redhat::inframanager::vm"=>
                #<ManageIQ::Providers::Redhat::InfraManager::Vm
                id: 1000000000023,
                ...>,
            :ext_management_systems=>
                #<ManageIQ::Providers::Redhat::InfraManager
                id: 1000000000001,
                ...>,
            :ems_event=>
                #<EmsEvent
                id: 1000000007999,
                event_type: "USER_RUN_VM",
                message: "VM rhel7srv010 started on Host rhelh03.bit63.net",
                ...>,
            "MiqEvent::miq_event"=>1000000008000,
            :miq_event_id=>1000000008000,
            "EventStream::event_stream"=>1000000008000,
            :event_stream_id=>1000000008000}>

Step 7

The new event is queued for processing by the Automation Engine (much of the work of the Automate Engine involves queueing and dequeuing further Automate work tasks):

MIQ(MiqAeEngine.deliver) Delivering {:event_type=>"vm_start",
              :"manageiq::providers::redhat::inframanager::vm"=>
              #<ManageIQ::Providers::Redhat::InfraManager::Vm
             ...
              :event_stream_id=>1000000008000} for object 
                 [ManageIQ::Providers::Redhat::InfraManager::Vm.1000000000023] 
                 with state [] to Automate

Step 8

The Automation Engine dequeues the task and instantiates the /System/Process/Event entry point into the Event Switchboard, along with the arguments assembled and passed by the build_evm_event internal method:

<AutomationEngine> Instantiating [/System/Process/Event?
  EventStream%3A%3Aevent_stream=1000000008000& 
  MiqEvent%3A%3Amiq_event=1000000008000& 
  MiqServer%3A%3Amiq_server=1000000000001& 
  User%3A%3Auser=1000000000001& 
  VmOrTemplate%3A%3Avm=1000000000023& 
  ems_event=1000000007999& 
  event_stream_id=1000000008000& 
  event_type=vm_start& 
  ext_management_systems=1000000000001&
  manageiq%3A%3Aproviders%3A%3Aredhat%3A%3Ainframanager%3A%3Avm=1000000000023& 
  miq_event_id=1000000008000& 
  object_name=Event& 
  vmdb_object_type=vm] 

Step 9

The Event Switchboard directs the processing to the /System/Event/MiqEvent/POLICY/vm_start instance, which does not exist by default (we could create one if we wished). The /System/Event/MiqEvent/POLICY/.missing instance is run in its place:

Following Relationship [miqaedb:/System/Event/MiqEvent/POLICY/vm_start#create]

Instance [/ManageIQ/System/Event/MiqEvent/POLICY/vm_start] 
                                not found in MiqAeDatastore - trying [.missing]

The .missing instance contains a rel2 relationship to /System/event_handlers/event_enforce_policy, so we follow the relationship chain:

Invoking [builtin] method [/ManageIQ/System/event_handlers/ 
                                        event_enforce_policy] with inputs [{}]

Step 10

The event_enforce_policy event handler initiates the processing of any control policies and alerts that may be associated with the event being handled.

This completes the event processing workflow for the internal vm_start event.

Event-Initiated Control Policy Processing

The next part of the event processing workflow handles any control policies that we might have associated with the event. This is where, for example, we would initiate a SmartState Analysis scan on a VM Create Complete policy event.

We can continue tracing the event processing from the previous sections, which started with an RHEV USER_RUN_VM event being caught. We saw “Step 10” calling /System/event_handlers/event_enforce_policy.

This method calls the internal process_evm_event method with a target argument corresponding to the VM object that raised the event:

MIQ(MiqEvent#process_evm_event) 
    target = [#<ManageIQ::Providers::Redhat::InfraManager::Vm 
                                                      id: 1000000000023, ...>]

Step 11

The process_evm_event internal method raises the vm_start (VM Power On) policy event and processes any actions (i.e., control policies) associated with the triggering of this policy event:

MIQ(MiqEvent#process_evm_event) Event Raised [vm_start]

In our case we have a VM control policy that runs an Invoke a Custom Automation action when the VM Power On event is triggered. The custom automation instance runs /Stuff/Methods/ObjectWalker (via /System/Request/Call_Instance). See Figure 15-8.

mcla 1508
Figure 15-8. VM control policy that links a VM Power On event to Run ObjectWalker

Step 12

The automation request to run Call_Instance is queued for processing by the Automation Engine. This is subsequently dequeued and delivered to Automate:

MIQ(MiqAeEngine.deliver) Delivering 
                        {"namespace"=>"stuff", 
                        "class"=>"methods", 
                        "instance"=>"objectwalker", 
                        :request=>"call_instance", 
                        "MiqPolicy::miq_policy"=>1000000000001} 
        for object [VmOrTemplate.1000000000023] with state [] to Automate

We see object_walker running in the automation.log file.

Event-Initiated Alert Processing

The final part of the event processing workflow handles any alerts that we might have associated with the event.

Step 13

The internal process_evm_event method now raises the vm_start (VM Operation: VM Power On) alert and processes any actions associated with the triggering of this alert:

MIQ(MiqEvent#process_evm_event) Alert for Event [vm_start]

In our case we have an alert that sends a management event called test when the VM Operation: VM Power On alert is triggered (see Figure 15-9).

mcla 1509
Figure 15-9. An alert to send a test management event

Step 14

The alert is queued for processing by the internal evaluate_alerts method, and our test event is run:

MIQ(MiqAlert.evaluate_alerts) [vm_start] Target: 
    ManageIQ::Providers::Redhat::InfraManager::Vm Name: [rhel7srv010], 
    Id: [1000000000023] Queuing evaluation of Alert: [VM Powered On]

This completes the full event processing workflow that started when the USER_RUN_VM event was detected from the RHEV provider. We saw the workflow pass through four stages: the handling of the external event, the raising and processing of the corresponding internal event, and the subsequent control policy and alert processing that may have been been associated with the event type.

Event-Initiated Automation Request Workflows

Automation Engine workflows that involve separated requests and tasks (see Chapter 12) also use raised events to control the processing sequence.

We can take a detailed look at the Automation Engine’s workflow by examining the steps involved in handling a RESTful API call to run the Automate /Stuff/Methods/Test instance.

We know that this type of API call will be handled in request and task stages, where the “task” is the actual running of our automation script. We also know that requests must go through an approval workflow. We can follow the sequence of steps through the processing of the various events using automation.log, and the helpful “Following…Followed” messages that the Engine prints.

Step 1: The request_created Event

The first messages that we see after the API call has been made notify us of the request_created event happening. We’re looking at CloudForms 4.0, so we see the new event stream information added to the event:

MIQ(AutomationRequest#call_automate_event) 
                Raising event [request_created] to Automate
MiqAeEvent.build_evm_event >> event=<"request_created"> 
                inputs=<{"EventStream::event_stream"=>1000000009327, 
                :event_stream_id=>1000000009327}>
MIQ(AutomationRequest#call_automate_event) 
                Raised  event [request_created] to Automate
Instantiating [/System/Process/Event? 
                AutomationRequest%3A%3Aautomation_request=1000000000029& 
                EventStream%3A%3Aevent_stream=1000000009340& 
                MiqRequest%3A%3Amiq_request=1000000000029& 
                MiqServer%3A%3Amiq_server=1000000000001& 
                User%3A3Auser=1000000000001& 
                event_stream_id=1000000009340& 
                event_type=request_created& 
                object_name=Event& 
                vmdb_object_type=automation_request]

Here we see the event being triggered, which takes us into the standard /System/Process/Event entry point instance. As we’ve seen, /System/Process/Event directs us into the Event Switchboard:

/System/Event/${/#event_stream.event_namespace}/ 
                                        ${/#event_stream.source}/${/#event_type}

Step 1.1

The variable substitutions are made from the EventStream object’s attributes, and we follow the relationship chain through the Switchboard:

Following Relationship [miqaedb:/System/Event/RequestEvent/Request/
                                                        request_created#create]

Step 1.2

The /System/Event/RequestEvent/Request/request_created instance contains a single rel5 relationship to /System/Policy/request_created. Once again we follow the relationship chain:

Following Relationship [miqaedb:/System/Policy/request_created#create]

Step 1.3

We are now in the /System/Policy namespace, which is where the event-specific policies are defined—that is, what to do when this type of event happens. Instances in this namespace typically have several entries (see Figure 15-10).

mcla 1510
Figure 15-10. The schema of the /System/Policy/request_created instance

A request_created event is raised for all types of request, so before any event-specific policy can be implemented, the type of request must be determined.

Step 1.4

The /System/Policy/request_created instance first runs the get_request_type method to find out what type of request has been created:

Invoking [inline] method [/ManageIQ/System/Policy/get_request_type] 
                                                                with inputs [{}]
<AEMethod [/ManageIQ/System/Policy/get_request_type]> Starting
<AEMethod get_request_type> Request Type:<AutomationRequest>
<AEMethod [/ManageIQ/System/Policy/get_request_type]> Ending

The get_request_type method returns Request Type:<AutomationRequest>.

Step 1.5

The next entry in the /System/Policy/request_created schema is the rel4 relationship to /System/Process/parse_provider_category, so we continue to follow the relationship chain:

Following Relationship [miqaedb:/System/Process/parse_provider_category#create]

Some event processing can be provider-specific; for example, we may wish to handle the same event in a different way, depending on whether it came from VMware or OpenStack. The rel4 relationship from /System/Policy/request_created takes us to the parse_provider_category instance to determine the provider.

The parse_provider_category instance runs the parse_provider_category method:

Invoking [inline] method [/ManageIQ/System/Process/parse_provider_category] 
                                                                with inputs [{}]
<AEMethod [/ManageIQ/System/Process/parse_provider_category]> Starting
<AEMethod parse_provider_category> Parse Provider Category Key: nil  
                                                                Value: unknown
<AEMethod [/ManageIQ/System/Process/parse_provider_category]> Ending

The parse_provider_category method returns a value of unknown, as this automation request does not involve any provider operations (as it would if we were provisioning a VM, for example).

Step 1.6

The final entry in the /System/Policy/request_created schema is the rel5 relationship to /System/Policy/AutomationRequest_created (AutomationRequest having been substituted for ${#request_type}).

This doesn’t exist, so we see this warning message:

Instance [/ManageIQ/System/Policy/AutomationRequest_created] not found in 
                                            MiqAeDatastore - trying [.missing]

We can create a /System/Policy/AutomationRequest_created instance if we choose, but in this case the .missing instance does nothing, so we end that event-initiated chain.

Step 2: The request_approved Event

The next event that we see is request_approved, which follows a very similar chain of relationships (we find that request_approved executes almost concurrently with request_created because we specified :auto_approve to be true in the automation request API call). Here we see the extract from evm.log:

MIQ(AutomationRequest#call_automate_event) 
    Raising event [request_approved] to Automate
MiqAeEvent.build_evm_event >> event=<"request_approved"> 
    inputs=<{"EventStream::event_stream"=>1000000009436,
    :event_stream_id=>1000000009436}>
MIQ(AutomationRequest#call_automate_event) 
    Raised  event [request_approved] to Automate
Instantiating [/System/Process/Event? 
    AutomationRequest%3A%3Aautomation_request=1000000000031& 
    EventStream%3A%3Aevent_stream=1000000009436& 
    MiqRequest%3A%3Amiq_request=1000000000031& 
    MiqServer%3A%3Amiq_server=1000000000001& 
    User%3A%3Auser=1000000000001& 
    event_stream_id=1000000009436& 
    event_type=request_approved& 
    object_name=Event& 
    vmdb_object_type=automation_request]

Step 2.1

Following Relationship [miqaedb:/System/Event/RequestEvent/Request/ 
                                                         request_approved#create]

Step 2.2

Following Relationship [miqaedb:/System/Policy/request_approved#create]

Step 2.3

Following Relationship [miqaedb:/System/Process/ 
                                                  parse_provider_category#create]
Invoking [inline] method [/ManageIQ/System/Process/ 
                                        parse_provider_category] with inputs [{}]
<AEMethod [/ManageIQ/System/Process/parse_provider_category]> Starting
<AEMethod parse_provider_category> Parse Provider Category Key: nil  
                                                                   Value: unknown
<AEMethod [/ManageIQ/System/Process/parse_provider_category]> Ending

Step 2.4

Following Relationship [miqaedb:/System/Policy/ 
                                               AutomationRequest_Approved#create]
Instance [/ManageIQ/System/Policy/AutomationRequest_Approved] not found 
                                            in MiqAeDatastore - trying [.missing]

The request_approved event processing doesn’t call get_request_type, as there is no need for type-specific processing at this stage.

Once again we have no AutomationRequest_Approved method, so we terminate this event-initiated chain at this point.

Step 3: The request_starting Event

The third event that we see is request_starting. At this stage we’re running within the context of an automation request; each of these log lines is preceded by the text Q-task_id([automation_request_1000000000031]).

MIQ(AutomationRequest#call_automate_event_sync) 
    Raising event [request_starting] to Automate synchronously
MiqAeEvent.build_evm_event >> event=<"request_starting"> 
    inputs=<{"EventStream::event_stream"=>1000000009437,
    :event_stream_id=>1000000009437}>

Instantiating [/System/Process/Event? 
    AutomationRequest%3A%3Aautomation_request=1000000000031& 
    EventStream%3A%3Aevent_stream=1000000009437& 
    MiqRequest%3A%3Amiq_request=1000000000031& 
    MiqServer%3A%3Amiq_server=1000000000001& 
    User%3A%3Auser=1000000000001& 
    event_stream_id=1000000009437& 
    event_type=request_starting& 
    object_name=Event& 
    vmdb_object_type=automation_request]

Step 3.1

Following Relationship [miqaedb:/System/Event/RequestEvent/Request/ 
                                                         request_starting#create]

Step 3.2

Following Relationship [miqaedb:/System/Policy/request_starting#create]
Invoking [inline] method [/ManageIQ/System/Policy/get_request_type] 
                                                                 with inputs [{}]
<AEMethod [/ManageIQ/System/Policy/get_request_type]> Starting
<AEMethod get_request_type> Request Type:<AutomationRequest>
<AEMethod [/ManageIQ/System/Policy/get_request_type]> Ending

Step 3.3

Following Relationship [miqaedb:/System/Process/ 
                                                  parse_provider_category#create]
Invoking [inline] method [/ManageIQ/System/Process/ 
                                        parse_provider_category] with inputs [{}]
<AEMethod [/ManageIQ/System/Process/parse_provider_category]> Starting
<AEMethod parse_provider_category> Parse Provider Category Key: nil  
                                                                   Value: unknown
<AEMethod [/ManageIQ/System/Process/parse_provider_category]> Ending

Step 3.4

Following Relationship [miqaedb:/System/Policy/ 
                                               AutomationRequest_starting#create]
Instance [/ManageIQ/System/Policy/AutomationRequest_starting] 
                                  not found in MiqAeDatastore - trying [.missing]

Step 3.5

MIQ(AutomationRequest#call_automate_event_sync) 
                                      Raised event [request_starting] to Automate

At the end of this chain we see the automation request queuing the automation task:

Q-task_id([automation_request_1000000000031]) 
    MIQ(AutomationTask#deliver_to_automate) 
        Queuing Automation Request: [Automation Task]...
Q-task_id([automation_request_1000000000031]) 
    MIQ(AutomationTask#execute_queue) 
        Queuing Automation Request: [Automation Task]...

Step 4: Automation Task Processing

Finally, we see the actual automation task running, which invokes our /Stuff/Methods/Test instance. At this stage, each of these log lines is preceded by the text Q-task_id([automation_task_1000000000034]) to indicate that we’re running within the context of an automation task:

MIQ(AutomationTask#execute) Executing Automation Request request: 
                                                                [Automation Task]
MIQ(AutomationTask#execute) Automation Request initiated
Instantiating [/Stuff/Methods/Test? 
    AutomationTask%3A%3Aautomation_task=1000000000034& 
    MiqServer%3A%3Amiq_server=1000000000001& 
    User%3A%3Auser=1000000000001& 
    object_name=test& 
    userid=admin& 
    vmdb_object_type=automation_task]
Invoking [inline] method [/Stuff/Methods/Test] with inputs [{}]
<AEMethod [/Stuff/Methods/Test]> Starting
<AEMethod test> This is a test!
<AEMethod [/Stuff/Methods/Test]> Ending
Method exited with rc=MIQ_OK

Extending Automate Event Handling

The provider-specific event stream source classes and associated instances under /System/Event/EmsEvent do not necessarily handle every possible event that can be raised by the provider. Sometimes we need to extend event handling to process a nondefault event.

We can extend the out-of-the-box event handling by creating our own instances under /System/Event (CloudForms 3.2) or /System/Event/EmsEvent/{Provider} (CloudForms 4.0) to handle these nondefault events caught by the EventCatcher workers.

As an example, the compute.instance.power_on.end OpenStack event is not handled by default with CloudForms 4.0. If we look in evm.log we see:

Instance [/ManageIQ/System/Event/EmsEvent/OPENSTACK/ 
   compute.instance.power_on.end] not found in MiqAeDatastore - trying [.missing]

As a result, the Cloud instance’s tile quadrant in the WebUI that shows power status doesn’t always change to reflect the instance being powered on.

Adding a New Automation Instance to /System/Event/EmsEvent/

There is already a ManageIQ/System/Event/EmsEvent/OpenStack/compute.instance.power_off.end instance to handle the compute.instance.power_off.end event. This instance calls two event_handlers (see Figure 15-11).

mcla 1511
Figure 15-11. Event handlers called by the compute.instance.power_off.end instance

We can copy this instance to our domain and rename it as /System/Event/EmsEvent/OpenStack/compute.instance.power_on.end (see Figure 15-12).

mcla 1512
Figure 15-12. Creating a compute.instance.power_on.end instance

We change the second event_handler line to trigger a vm_start policy event (see Figure 15-13).

mcla 1513
Figure 15-13. Editing the event handlers as required

Now when we power on an OpenStack instance, we see the instance’s tile quadrant change correctly, and we see the raising and processing of the vm_start event:

Instantiating [/System/Process/Event? 
    EventStream%3A%3Aevent_stream= 
                           1000000009501&MiqEvent%3A%3Amiq_event=1000000009501& 
    MiqServer%3A%3Amiq_server=1000000000001& 
    User%3A%3Auser=1000000000001& 
    VmOrTemplate%3A%3Avm=1000000000035& 
    ems_event=1000000009500& 
    event_stream_id=1000000009501& 
    event_type=vm_start& 
    ext_management_systems= 1000000000002& 
    manageiq%3A%3Aproviders%3A%3Aopenstack%3A%3Acloudmanager%3A%3Avm= 
                                                                 1000000000035& 
    miq_event_id=1000000009501& 
    object_name=Event& 
    vmdb_object_type=vm]

This will ensure that any control policies that are triggered by a VM Power On event will run correctly.

Summary

Phew! This has been a long theoretical chapter that has taken us on a detailed tour of how the Automation Engine handles events.

We have familiarized ourselves with the component parts of the new event handling mechanism in CloudForms 4.0. We have seen how external provider events are detected (“caught”) and handled, and we have followed the event processing workflow from the detection of an RHEV provider event through the raising of the corresponding internal event and seen how related control policies and alerts are processed.

We have seen that Automate actions involving separated requests and tasks also use event-initiated workflows, and we have seen how to extend event handling to handle additional events.

Next Steps

This concludes Part I of the book. We now have enough knowledge of the Automate Datastore and the structures, concepts, and objects it comprises to be able to tackle most automation challenges.

In Part II we will put this knowledge to good use and start investigating the Automate operations involved in provisioning a virtual machine.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.4.174