Skip to end of metadata
Go to start of metadata

Project Overview

Currently, the Asterisk REST Interface (ARI) has the ability to retrieve information from Asterisk, but cannot manipulate it. Modifying Asterisk through ARI would be a handy thing to do, which is what this project intends to achieve. To start off, modules and logging channels will be looked at, with the ability to load, unload, and reload modules, as well as the ability to add, retrieve, and rotate log channels.

Requirements Specification

Module Operations

ARI will be able to load, unload, and reload modules for Asterisk, as well as retrieve information for modules.

The only thing the ARI user will need to know is the name of the module he/she wishes to act upon.

Example

GET /ari/asterisk/modules
POST /ari/asterisk/modules/pbx_config.so
PUT /ari/asterisk/modules/chan_pjsip.so
DELETE /ari/asterisk/modules/chan_sip.so

What should happen:

  • GET - Returns information for all loaded modules. The path can be extended (ex. /ari/asterisk/modules/app_stack) to get information on a specific module.
  • POST - The load module functionality. If you don't have a module loaded that you need, use this.
  • PUT - The reload functionality. Refresh, refresh, refresh.
  • DELETE - The unload functionality. Not using a module anymore? Unload it with DELETE!

Logging Operations

ARI should also be able to add log channels, retrieve them, and rotate them.

Example

GET /ari/asterisk/logging
POST /ari/asterisk/logging/mylog?configuration=notice,error,warning
PUT /ari/asterisk/logging/mylog/rotate
DELETE /ari/asterisk/logging/mylog

What should happen:

  • GET - Returns information for all active log channels. Information on a single log channel can be retrieved the same way as a single module.
  • POST - Creates a log channel. Name it whatever you want. Can also set the different levels it will monitor.
  • PUT - Rotate a log channel.
  • DELETE - Deletes the log channel.

Configuration

No configuration should be needed other than what is necessary for ARI.

Design/Implementation

Swagger Model Updates

The asterisk resource will be modified, adding two new sections: modules and logging.

This is subject to change.

asterisk.json

Testing

TestPathPurpose
/asterisk/modules/get_modulestests/rest_apiVerify that Asterisk returns a list of loaded modules.
/asterisk/modules/get_moduletests/rest_apiVerify that Asterisk returns information on a module, whether it is loaded or not.
/asterisk/modules/get_unknown_moduletests/rest_apiVerify that trying to get information on a non-existent module returns a warning message saying that the module does not exist.
/asterisk/modules/load_moduletests/rest_apiVerify that a module is loaded to Asterisk, assuming it was not already loaded.
/asterisk/modules/load_already_loaded_moduletests/rest_apiVerify that loading a module that is already loaded results in a warning message saying that the module already exists.
/asterisk/modules/load_unknown_moduletests/rest_apiVerify that trying to load a module unknown to Asterisk results in two warning messages saying that the file does not exist, and Asterisk could not load the module.
/asterisk/modules/unload_moduletests/rest_apiVerify that a module was unloaded from Asterisk, assuming it was not already unloaded.
/asterisk/modules/unload_already_unloaded_moduletests/rest_apiVerify that unloading a module that is already unloaded results in a warning message saying that the unload failed, and that the module could not be found.
/asterisk/modules/unload_unknown_moduletests/rest_apiVerify that trying to unload a module unknown to Asterisk results in a warning message saying that the unload failed, and the module could not be found.
/asterisk/modules/reload_moduletests/rest_apiVerify that a module was reloaded to Asterisk.
/asterisk/modules/reload_unloaded_moduletests/rest_apiVerify that reloading a module that is unloaded from Asterisk results in a warning message saying that the module does not exist.
/asterisk/modules/reload_unknown_moduletests/rest_apiVerify that trying to reload a module unknown to Asterisk results in a warning message saying the module does not exist.
/asterisk/logging/get_loggingtests/rest_apiVerify that information on all log channels was retrieved.
/asterisk/logging/get_logging_channeltests/rest_apiVerify that information on a single log channel was retrieved.
/asterisk/logging/get_unknown_logging_channeltests/rest_apiVerify that trying to retrieve information on a non-existent log channel results in a warning message saying the log channel does not exist.
/asterisk/logging/add_loggingtests/rest_apiVerify that a log channel was added to a channel or bridge.
/asterisk/logging/add_already_existing_loggingtests/rest_apiVerify that trying to add a log channel that already exists (has the same name) results in a warning message saying the channel already exists, and the channel could not be added.
/asterisk/logging/add_logging_invalid_leveltests/rest_apiVerify that trying to add a log channel with a logging level that is unknown to Asterisk results in a warning message saying a logging level was invalid, and that the channel could not be added.
/asterisk/logging/rotate_loggingtests/rest_apiVerify that a log channel was rotated from a channel or bridge.
/asterisk/logging/rotate_unknown_loggingtests/rest_apiVerify that trying to rotate a non-existent log channel results in a warning message saying the log channel does not exist, and the channel could not be rotated.

 

Project Planning

In order for logging and module functionality to be a full fledged ARI Asterisk resource feature it must be planned out accordingly through testing, updating possible non-ARI changes, and lastly updating the ARI information. These processes will be implemented separately to ease the process of peer review.

Phase 1: Writing Tests

We’re still unsure if this is the best way to go about working on this project, but it seemed like a good start for us to wrap our heads around the functionality of modules and logging information.

The tests will be REST API tests.

Phase 2: Updating the ARI Information

Update the ARI information at hand. This phase will consist of generating new swagger bindings, updating the JSON file for the asterisk resource, and finally implementing the system to contain all of the functionality needed for ARI to retrieve information and manipulate that information efficiently. Leave stubs for future implementation.

Phase 3: Updating Possible Non-ARI Changes

The task may require adding some methods to the main code in asterisk. Once again we aren’t sure on this fact but we have to find a way in which we can retrieve the active channel logs and running modules. So, this step may be necessary in the process of the project.

Phase 4: Implementing ARI Stubs

Go back and implement the stubs in phase 2. This will tie everything together, allowing useful information returns when testing the new functionality.

Documentation

From the perspective of an ARI user, I would want to see a list of operations I can perform, the syntax for those operations, the possible values I could pass in, and examples of these new features being used so that I could use them as a reference for getting my own applications started.

 

  • No labels

16 Comments

  1. Modifying Asterisk through ARI would so a handy thing to do

    Awkward sentence

    POST /ari/asterisk/modules/load?module=pbx_config
    PUT /ari/asterisk/modules/reload?module=chan_pjsip

    What is supposed to happen with these operations?  PUT does reload?  POST does load?

    Logging

     I'm not sure how much dynamic logging currently exists in Asterisk.  These are the logging channels like VERBOSE, DEBUG, FAX, CCSS?

     

    1. Thanks for the feedback!

      That sentence had a typo, thanks for catching that.

      Added a description for the modules example.

      As far as logging goes, I think we looked at it the wrong way. Back to the drawing boards. We'll give a shout on swdev when we've fixed this.

  2. Your documentation for log channel says:

    POST - Creates a log channel. Name it whatever you want. Can also set the different levels it will monitor.

    But the swagger definition has a fixed list of allowable values, which I'm pretty sure will prevent the user from supplying an arbitrary name not on the list.

  3. Hey guys, this all looks like a good start for things.

    We'd also like to be able to do this with multiple variables, especially modules, so that an ARI user can load multiple modules at once, or unload, or whatever it is they want to do.

    I think this is one of those things that probably will not be necessary. Also, given the proposed scheme for the "modules" resource, this seems like it would not be an easy thing to do.

    What should happen:

    • GET - Returns information for all active log channels.
    • POST - Creates a log channel. Name it whatever you want. Can also set the different levels it will monitor.
    • PUT - Rotate a log channel.

    I'm not so sure I like the current scheme here, mainly because to me, if I saw "PUT /asterisk/logging/mydebuglog", my instinct wouldn't be that this would rotate the log file. Rotating a log file is one of those cases where the HTTP verb on its own isn't enough to convey what is happening, and so it may make more sense to have an addition to the resource, such as "PUT /asterisk/logging/mydebuglog/rotate".

    From asterisk.json:

                            "allowableValues": {
                                "valueType""LIST",
                                "values": [
                                    "debug",
                                    "notice",
                                    "warning",
                                    "error",
                                    "dtmf",
                                    "fax",
                                    "security",
                                    "verbose"
                                ]

    As we discussed this morning, the allowable values for the logger level are actually not restricted to the ones you've listed since logger levels can be registered dynamically by any Asterisk module. Trying to keep tabs on what values are allowed is probably not advised at this level. Rather, accept any string and potentially return some sort of HTTP error response if someone has specified a logger level that is currently unknown.

    I think your test phases look good, but I'd probably swap phases 2 and 3, and I'd put an extra step 4 on there. Here's how I'd list the steps

    1. Write the tests
    2. Add the new REST calls to ARI, with the backend implemented just as stubs. This way, you can actually point your tests at Asterisk and make sure there isn't any sort of problem with the HTTP frontend or any bugs in the tests themselves. The REST API tests won't be able to verify that any useful data is returned or set, though.
    3. Add any additional internal Asterisk functionality if necessary. If possible, you can also write unit tests for these new function calls you add to Asterisk to ensure that a set of inputs gives the expected outputs.
    4. Fill in the stubs from step 2 to use the new internal Asterisk functions. From here, you can rerun your REST API tests and now can ensure that the data you get/set is what you expect.

    Now to address things that aren't currently on the page.

    As you pointed out, the asterisk.json is currently incomplete, so I won't pick it apart too much. Probably the biggest thing you'll need to still define is what the model for an Asterisk module is (i.e. what will be returned by a GET of Asterisk modules)

    As Matt pointed out in the meeting this morning, it may be a good idea for /asterisk/modules/ to be able to GET a specific module's information. This can act as a quick means for a developer to check if a specific module is running.

    One thing to consider for testing is off-nominal paths. Right now, your test plan seems to focus on ensuring that valid inputs result in valid behavior. If you haven't already, you may want to think about what the proper behavior would/should be in the cases where improper input is given. It's a good idea to also attempt testing bad behavior, like

    1. Try to retrieve module data for a non-existent module
    2. Try to load a non-existent module
    3. Try to reload a module that isn't currently loaded
    4. Try to create a log channel with an invalid level
    5. etc.

    With log channels, since asterisk.json currently says that multiple parameters may be specified, you'll want to try running a test where you attempt to add two log channels in a single HTTP POST. One log channel is perfectly valid, but the other has an error in it. You'll want to make sure that a failure is an absolute failure in this case by making sure that not only did the improper log channel not get added but that the valid one did not as well.

     

  4. I think you're at a point where you definitely have a good firm foundation for the project. I noticed that you expanded on asterisk.json. The one thing I'd recommend is that you expand on the "Module" datatype to have more information than just the name. When you issue the CLI command "module show like res_pjsip.so" you get the following info:

    *CLI> module show like res_pjsip.so
    Module                         Description                              Use Count  Status      Support Level
    res_pjsip.so                   Basic SIP resource                       22         Running              core

    I would include all of this information when retrieving a module.

    One thing that's a bit confusing in your test table is that there are multiple tests with the same name but that do different things. I'd rename tests to more clearly indicate the goal of the test.

    Other than that, I'd say everything else looks good to move on to the next phase. Great job!

    1. Thanks Mark! Everything should be updated now.

  5. Even though I know what you mean here, I think that this may be misleading to others if it is taken literally:

    DELETE - The unload functionality. Not using a module anymore? Delete it!

    Maybe rephrase to something like:

    DELETE - The unload functionality. Not using a module anymore? Unload it with DELETE!

    1. Thanks, we made the update!

  6. In the 'Module Operations' section:

    ARI will be able to load, unload, and reload modules for Asterisk, as well as retrieve information for modules.

    The only thing the ARI user will need to know is the name of the module they wish to modify.

     

    Since you are going to give users more than just the ability to modify a module (they can load, reload, unload, retrieve information, and probably influence state somehow), I think that you should use the verb 'act upon' instead of 'modify':

    ARI will be able to load, unload, and reload modules for Asterisk, as well as retrieve information for modules.

    The only thing the ARI user will need to know is the name of the module they wish to act upon.

     

    P.S. Technically, ARI user is singular, so 'they' and 'wish' should be 'he/she' and 'wishes' (tongue)

     

  7. In the Swagger definitions for load, unload, and reload, is there a possibility that there would need to be other errors besides 404? For example, what if the module failed to load due to configuration issues?

    1. Thanks for addressing that, and we haven't really taken as much time yet on the error codes needed at the moment. The 404 code was to just lay the groundwork for where our error responses will be located within the json file. So, once we finally implement the json we'll definitely take into account the 'failed to load' issues and a bunch others as well.

      1. Okay. I figured making a comprehensive list of the reasons a module might not load wouldn't be within the scope of this draft of the document. That may take a little bit of research to dig around and find out all the reasons a module fails to load.

        It may be worth noting that there could be reasons that are impossible to anticipate - e.g. a custom module is added and it couldn't load because of it's own custom criterion that a foo must come before a bar. So, maybe for cases like these, there could be some mechanism for injecting custom error messages into the ARI framework when a module is unable to load, to use in conjunction with a general purpose error code (maybe 500?). Granted, I haven't really thought this through 100% - just putting it out there.

  8. There is no mechanism addressed in this document for removing a logging channel from use - is this something that we might want to look into?

  9. I think removing a logging channel should indeed be in there.

    1. Would this involve deleting the entire log channel or just unregistering a logger level like you were discussing earlier?

       

      1. It should delete the log channel. Unregistering a log level is probably impossible for ARI, as some other module is providing that log level.