Page tree
Skip to end of metadata
Go to start of metadata

Flexiant Development Language (FDL) is a Lua based language that allows you to extend Flexiant Cloud Orchestrator.

Lua (pronounced 'loo-er') is an easy to use but powerful, fast, and lightweight, embeddable scripting language. More details on Lua can be found here. Flexiant Cloud Orchestrator uses Lua 5.2.


Learning Lua

This section will not teach you how to program in Lua. For resources on programming in Lua, we recommend you:

  • Look at the Lua website;
  • Buy a book about Lua; or
  • Look at this ebook (this refers to Lua 5.0 not 5.2, but the language has changed little).

Introduction to FDL

You can write FDL either using the FDL Code Blocks Widget, or by cut and pasting from your favourite text editor. In this way you can create one or more FDL code blocks. For information about how Flexiant Cloud Orchestrator uses FDL code blocks as part of the billing system, see Products, Product Offers, and Billing.

You will notice that the system supplies one or more default FDL code blocks. These are marked read only (this is so that on an upgrade, we know we can replace them without overwriting any of your changes). However, you can duplicate them using the 'duplicate' button on the modal, and then edit the duplicate.

An FDL code block consists at the minimum of a register function. The register function returns references to zero or more other functions within the FDL code block, each of which describes an entry point.

Any example of a register function (from our default code block) is shown below:

function register ()
        return {
                "fixedResourceBilling",
                "serverAllocatedCPUBilling",
                "serverAllocatedRAMBilling",
                "sizeAllocatedBilling",
                "diskIOUsageBilling",
                "networkIOUsageBilling",
                "unitTopUpBilling",
                "fetchResourceBilling",
                "customerResourceAssetBilling",
                "subnetBillingIpV4"
        }
end

As you can see, it simply lists the names of the functions used as entry points.

Each entry point is called under two circumstances:

  • It is called on initialisation with no parameters, in which case it describes itself. It does this by returning a Lua table which describes the FCO FDL API in use, the API version, the function to call, and various API dependent parameters.
  • It is called to do 'real work' (what that is depends on the API), in which case it is called with a Lua table (called p) which are the parameters. What these parameters are depends on the API.

For example, the default code block provides FDL billing API entry points. These each implement a billing method. The first of these is set out below:

-- This is the most simplistic billing function, it will charge a fixed amount each time it is
-- invoked, and can be used with any product component.
function fixedResourceBilling(p)
        if (p == nil) then
                local confvalues = {getInitialUnitsDefinitionTable(), getRepeatUnitsDefinitionTable()}
                return {
                        ref="_fixedResourceBilling",
                        name = "Fixed billing for resources",
                        description = "Charge the same number of units in each billing period",
                        permittedPCT = nil,
                        configuredValues = confvalues,
                        api = "BILLING",
                        version = 1
                }
        end
        
        print ("Last Billing Time is : " .. p.lastBillingTime .. " Billing Factor is "..p.billingFactor)
        if (p.lastBillingTime == 0) then
                cunits = getInitialUnits(p.billingComp)
                if (cunits > 0.0) then
                        return {{units = cunits * -1, description="Initial charge"}}
                end
        else
                cunits = getRepeatUnits(p.billingComp)
                if (cunits > 0.0) then
                        return {{units = cunits * -1 * p.billingFactor , description = "Charge for period" }}
                end
        end
        return nil
end

Lines 4 to 16 inclusive deal with the situation where the entry point fixedResourceBilling is called with no parameters, and is hence being asked to describe itself. This does the following:

  • Initialises a table of configured values using two helper functions which construct a standard table for initial units and repeat units.
  • Return a table containing
    • A reference identifier _ref which uniquely identifies the billing method concerned (so that if a new code block is loaded in, it knows which one to replace).
    • A name and a longer description for the billing method.
    • A table setting out which product components it can be used with (in this case nil meaning all of them).
    • The configured values as set out above.
    • The name of the API (in this case BILLING).
    • The version of the API (1).

The remainder of the function deals with calculating how many units to bill for a given billing period in respect of a resource, i.e. it implements a billing method. In brief:

  • If no previous billing time (p.lastBillingTime) is offered, then it will bill an initial charge (using the helper function provided).
  • If a previous billing time is provided, it will bill the amount of repeat units. This is multiplied by a billing factor, which is the ratio of the time between the two measurements and the billing period (as determined from the product offer).
  • In both instances the number of units is multiplied by -1 to indicate that the result should be subtracted.
  • In both instances a description is returned.

A longer example can be found at Example Billing Method.

Features of FDL common to all APIs

The following is common to all FDL APIs:

  • Anything you print (to STDOUT or STDERR) will go to the Jade sysout log.
  • You can log any string to the normal log with logger (which takes a string).
  • If your Lua throws an exception, Jade will catch it. However, you should aim not to throw exceptions but instead return something appropriate depending on the API.
  • Your entry point will always be called with a single parameter p dependent on the API being called, or a value of nil.
  • If a value other than nil is passed, the return value of the function depends upon the API.
  • If a value of nil is passed, the function is expected to return a table which describes itself. This should contain the following keys:
    • api: the name of the API as a string (for instance "BILLING")

    • version: the version of the API as a number.
    • ref: a unique identifier for the function. 

      Do not use identifiers starting with an underscore; these are reserved for Flexiant.

    • name: a string containing the name of the entry point (max 50 characters)
    • description: a string containing a description of the entry point (maximum 250 characters)
    • executionFunction: a reference to a LUA function which is the function to call with values of p other than nil. If this is not specified or is specified as nil, then the same function will be called.

The range of Lua modules imported depends upon the API in use.

The FDL Billing API

The FDL Billing API has the following features:

  • The name of the API is "BILLING"
  • The version of the API is 1
  • Returning from an entry point with api set to BILLING makes the entry point a billing method.
  • Entry points which are billing methods should also return the following data when describing themselves:
    • configuredValues: a table of value objects, which represent the configurable values associated with the billing method. Omitting this or specifying it as nil will result in no configured values being associated with the billing method.
    • permittedPCT: a table which is a list of permitted product component types. If this is omitted or nil then the billing method can be used with all product component types.
  • The value object has the same layout as in the API. See SOAP value. Each value object specifies a configurable value, together with its validator (setting out the permissible values for it).

FDL Billing API calls are called once per billing cycle per product component per resource. They should therefore execute quickly. Lua performs very efficient table lookups and arithmetic, and writing even moderately complex functions should not present a performance problem. You should however avoid attempting to perform operations which open external files, or do other time-consuming activities.

The FDL Trigger API

The FDL Trigger API has the following features:

  • The name of the API is "TRIGGER"
  • The version of the API is 1
  • Returning from an entry point with api set to TRIGGER makes the entry point a trigger.
  • Entry points which are triggers should also return the following data when describing themselves:
    • triggerType: a type of event that initiates a trigger, for example an API call or a change in resource state. This can be refined using the triggerOption object, which states the specific events that can initiate the trigger. 
    • triggerOptions: a list of the specific events that can initiate a trigger. For example, if the triggerType indicates that the trigger can be initiated by a server state change, the triggerOptions determine which server states initiate the trigger. For more information, see Trigger type options.
  • The value object has the same layout as in the API. See SOAP value. Each value object specifies a configurable value, together with its validator (setting out the permissible values for it).

PRE triggers are always done synchronously before a resource changes state. This means that PRE triggers can affect the time taken to perform an action. POST triggers are performed asynchronously and therefore should not affect performance. 

Improper use of triggers can severely disrupt your access to the platform, so be aware of the /etc/extility/local.cfg option JADE_ALLOW_TRIGGERS, which can be used to turn triggers on or off on a global basis. This value defaults to 1.

The following is a list of the various triggerTypes, and whether the trigger is initiated before (PRE) or after (POST) the initiating event:

Initiating eventtriggerTypePRE triggersPOST triggers
Creation of a resourceCREATEYesYes
Modification of a resourceMODIFYYesYes
Deletion of a resourceDELETEYesYes
Making an API callUSER_API_CALL or ADMIN_API_CALLYesYes

Jade exception

Exceptions thrown by triggers cannot initiate other triggers.

EXCEPTIONNoYes
Scheduled based on elapsed time intervalSCHEDULEDNoYes
Making a paymentPAYMENTYesYes
Purchasing unitsPURCHASEYesYes
Adding units to a customer's accountUNIT_TRANSACTIONNo Yes
Job state changeJOB_STATE_CHANGEYesYes
Authorisation of a customer accountAUTHYesYes
Server state changeSERVER_STATE_CHANGEYesYes
Server initialisation before metadata is passed to the booting serverSERVER_METADATA_UPDATEYesNo
Iteration of billing cycle (automatic)BILLINGNo Yes
Iteration of invoice collection cycle (automatic)COLLECTIONNo Yes

For more information about triggers, see Triggers. For an example of a complete trigger, see Example Trigger.

The FDL Payment API

The FDL Trigger API has the following features:

  • The name of the API is "PAYMENT"
  • The version of the API is 1
  • Returning from an entry point with api set to PAYMENT makes the entry point a payment provider.
  • Entry points which are payment providers should also return the following data when describing themselves:
    • configuredValuesPM: a table containing the keys and values of the fields that a billing entity is required to complete when they create a payment method based on the payment provider.
    • configuredValuesPMI: a table containing the keys and values of the fields that a customer is required to complete when they create a payment option based on the billing entity's payment method.
  • The value object has the same layout as in the API. See SOAP value. Each value object specifies a configurable value, together with its validator (setting out the permissible values for it).

States affect Jade depending on what is returned, for example a payment can complete successfully, but if the payment provider returns SUSPEND, Jade will not recognise that the job has completed. As Jade will eventually decide that the job has taken too long to complete and time out, this can result in a situation where the job has failed when payment has been taken from the customer.

  • No labels