Examples

Introduction

The Lua scripting engine is a powerful tool for extending the features of the OCS to perform custom actions within the OCS engine. It is, however, sometimes opaque how to use the Lua API.

The following examples ideally give some idea of how the OCS Lua API can be used to achieve new functionality in the OCS.

Immediately Transition to a New Lifecycle State

A lifecycle action might, for testing or temporary purposes, need to transition immediately to a new state once entered. This might be useful if a lifecycle state is simply used as a marker for EDR purposes.

To achieve an immediate transition, create a lifecycle action which immediately succeeds with the transition event name. Given two states, A and B, with a transition from A to B done by an event named a_to_b, the following lua action (created on A) will achieve this:

local ocs = require "n2.n2ocs"
local f = function (context)
    ocs.succeeded("a_to_b")
end
return ocs.create_lifecycle_action_handler(f)

Trigger the Removal of the Lifecycle Owner

To remove a subscription from an wallet, or to remove an wallet from the OCS, the associated subscription or wallet lifecycle normally itself would determine it should be delete (resource API methods exist on the OCS to remove wallets and subscriptions from wallets, but these methods are designed for provisioning and data administration and not BAU).

To remove the owner of a lifecycle then, a lifecycle action must trigger the removal. To do this, the action uses the delete() method of the lifecycle instance.

The delete() method is available on lifecycles other than the current lifecycle too, so it is possible to trigger this deletion on lifecycles other than the active one.

local ocs = require "n2.n2ocs"
local f = function (context)
    context.active_lifecycle_instance().delete()
end
return ocs.create_lifecycle_action_handler(f)

This is often the action of a lifecycle’s DELETE or REMOVE state.

Set a Lifecycle State’s Transition Date/Time

A lifecycle state might require it’s transition time to be dynamically set for some reason. To achieve this, use the set_transition_out_time() method, passing in the expiry as either a fixed date/time (based on seconds since Jan 01 1970), or as a table describing how to calculate the expiry.

For example, to set the expiry to be 100 days from the moment the action runs for a lifecycle:

local ocs = require "n2.n2ocs"
local f = function (context)
    local expiry = { days = 100 }
    context.active_lifecycle_instance().set_transition_out_time(expiry)
end
return ocs.create_lifecycle_action_handler(f)

Trigger Notification Before Bucket Expiry

If a bucket is created with a lifecycle using the supplementary-lifecycle annotation, then the bucket lifecycle will process. A lifecycle can define a fake transition that does not actually transition, but rather triggers a pre-expiry notification.

The lifecycle transition can be configured using the following JSON:

{
    "id": "pre_expiry_notification_3d",
    "event": "pre_expiry_notification_3d",
    "timer": {
        "days": 3
    },
    "timer_reference": "transition_out_time",
    "action": "-- see below",
    "action_language": "lua"
}

In this transition the timer defines a transition of 3 days and because it is special (it is against the transition_out_time it occurs 3 days before the transition out time.

Lua code to run as the action can then send the notification:

local jslee = require "n2.jslee.JSLEE"
local ocs = require "n2.n2ocs"
function trigger(context)
    local bucket = context.active_lifecycle_target()
    if (bucket.is_bucket() and bucket.as_bucket().expiry() ~= nil) then
        local notification = {
            wallet_id = context.active_wallet().id(),
            bucket = bucket.as_table()
        }
        ocs.notify("pre_expiry_notification", "3d", notification)
    end
end
return ocs.create_lifecycle_action_handler(trigger)

Note that the handler does not use ocs.succeeded() to trigger an actual transition. Instead, this action runs once, (at 3 days prior to expiry, or as soon as the wallet is accessed after this instant), and on execution will send a notification with both the wallet ID and the bucket information that triggered the notification.

Credit a Subscriber Wallet

One of the features of the N-Squared OCS is that subscription processing is controlled by state machines that are (a) defined dynamically through configuration and (b) control the execution of actions such as debiting and crediting wallets using scripts executed during the processing of these state machines.

To perform a credit as part of a lifecycle (one that is likely attached to a subscription/service), script code uses the engine’s .credit() method.

local ocs = require "n2.n2ocs"
local engine = require "n2.n2ocs.engine"

local action = function(context)
    local sub = context.active_subscription()
    local svc = subscription.service ()
    local request = {
        credit_requested = context.ancillary_information ().buckets
        credit_context = {
            derived_from = "service," .. svc.id .. "," .. svc.name
        }
    }
    local ok, error = engine.credit (request)
    if not ok then
        -- transition to the grace state.
        -- An error EDR would already have been generated by the system
        ocs.succeeded('grace')
    else
        -- transition to the granted state
        -- this will then automatically transition out in N days.
        ocs.succeeded('granted')
    end
end
return ocs.create_lifecycle_action_handler(action)