Here is the list of REST API that's currently available in CMS. This article gives you instructions on how to add a new REST end point in CMS.

Add A New Type of Element to be managed by REST CMS

From this diagram, you can actually see the FOUR major components you need to create in order to have your element managed by the REST CMS: a controller, a configuration manager, a configuration validator and a configuration realizer. 

Configuration Controller

In order to add a rest end point, we will need a controller entry point to handle the request. You can see RegionManagementController as an example. Here is a few things you need to pay attention to:

  1. @ApiOperation: this is to make your rest end point available in Cli. The value attribute of this annotation will be the name of the command line to invoke this rest end point. If this rest end point is a list/get type of operation, you can provide an optional 'jqFilter' attribute to filter out the json response as a tabular result to this cli command. Command line users can override this jqFilter by providing their own when executing this command, this attribute is there only as a default filter.
  2. @PreAuthorize: specifies the permission needed to execute this rest end point.
  3. Don't put too much logic in the controllers. The controller should simply use the request parameters, form them into the arguments that cluster management service API accepts and return the results.

The moment you want to call the CMS API, you find yourself in need of  two basic types for your Element: a Configuration object and a RuntimeInfo.

Configuration Object

This objects specifies how you want to configure this element like Region, Index, GatewayReceiver etc. To get started, consider only adding those attributes that you want to expose through rest api. For example, although according to the cache.xsd, a region can be configured with many attributes (see RegionConfig, which is generated by the jaxb service using the cache.xsd file), in rest management api, we don't want to overwhelm users, so we only expose those that are more commonly used. That would require us to expose a different configuration object called Region (better to put all configuration object in one package). 

Your configuration object should either extend AbstractConfiguratioin if you can only configure one of it in the entire cluster (like PDX, can only be defined in the cluster level), or GroupableConfiguration if there could be one per server group (like region). There are also interfaces your configuration needs to consider adding: RegionScoped and HasFile. If your configuration lives under the Region element in cache.xml (like Index), then your configuration object needs to implement RegionScoped. If your object has file content (like Deployment), then it needs to implement HasFile.  Note if your object implement RegionScoped, then you need to extend AbstractConfiguration, not GroupableConfguration.

When you create your Configuration object, you notice you will need to type it with a RuntimeInfo. This is used to tell the framework what's the corresponding RuntimeInfo object this configuration object is related to. For example, Region is related to RuntimeRegionInfo, which give more information about the state of the region on each server, that's why Region extends GroupableConfiguration<RuntimeRegionInfo>. If your configuration object doesn't have any corresponding runtime information, you can simply type it with the abstract class itself, like <code>class XYZ extends AbstractConfiguration<RuntimeInfo></code>.

RuntimeInfo Object

Like said above, this object collects runtime information about this configuration object on each server. For example, entry count for the region, specific jar location on each server about each deployment etc. If you don't need to collect any runtime information for your configuration object, you don't need to implement this.

Configuration Manager

Now that you have the configuration object ready, you will need to create a ConfigurationManager that tells the framework how this object is to be managed by the configuration service. If your configuration object is part of the cache xml, your configuration manager should extend CacheConfigurationManager. If your object affects other parts outside cache.xml, like jar deployment or runtime properties, you will need to extend its parent class ConfigurationManager.

For now, after you created a configuration manager, you will need to manually add it to the map of managers in LocatorClusterManagementService.

Note the configuration managers are run on the locators.

CacheConfigurationManager

To extend this class, you will need to implement a few methods, basically to tell the framework how your element will be added/deleted/updated/found in the CacheConfig (an object represent the cache.xml). You can see examples in RegionConfigManager. In there you find yourself in need of a ConfigurationConverter.

ConfigurationConverter

ConfigurationConverter specifies how you convert between your configuration object and the xml representation of it.

As we mentioned before, we don't use jaxb generated object as our configuration object but create our own configuration object. Since CacheConfig uses these jaxb-generated objects inside (because they are all auto-generated by the jaxb service), we will need a way to convert our configuration object to/from these xml objects. Hence, in order to implement the CacheConfigurationManager, we will need a converter first. You can also the usage and the implementation of a converter in RegionConfigManager. 

ConfigurationManager

If your configuration is not part of the cache.xml, but something else, like deployment or runtime properties, you will need to implement this interface instead.

Configuration Validator

Configuration Validator is called when CMS receives the configuration for operations like create or delete. You can use this to validate if the attributes set on the configuration is valid or not.

For now, after you created a configuration validator, you will need to manually add it to the map of validators in LocatorClusterManagementService.

Note the configuration validators are run on the locators.

Configuration Realizer

Configuration Realizer controls how the entity represented by this configuration is created/deleted/updated on the servers. For example, after we have this region configuration, how we actually create it on the servers. See RegionConfigRealizer.java for example. 

For now, after you created a configuration realizer, you will need to manually add it to the map of validators in CacheRealizationFunction

Note the configuration realizers are run on the servers.

Add A New Long Running Operation to be started by REST CMS

You can also start a long running operation through CMS REST call. Currently, we have restore redundancy and rebalance operations. If you want to add another long running operation to be started asynchronously and have the user check back for status through the rest end point, you will need to add these: a controller and a performer.

Operation controller

This handles the REST request and response. See RebalanceOperationController for example. The same list of things to pay attention to in configuration controller also applies here as well.

When you want to call into the configuration service's API to start the operation, you find yourself in need to of two object: ClusterManagementOperation and OperationResult

ClusterManagementOperation

This object defines the operation you want to run on the cluster. See RebalanceOperation for example. This object needs to be typed with the result object explained below.

OperationResult

This object holds the information you want to return to the user about the operation result when this operation finishes. See RebalanceResult for example.

Operation Performer

Now that you've created the operation and result object, you can now implement a performer that would take this operation object and return the result. Your performer needs to implement the OperationPerformer interface. See RebalanceOperationPerformer for example.

For now, after you created the performer, you will need to manually register it in the operation manager

Note the performer is run on the locators, and if you need to invoke operations on the servers, you will need to have all that logic in your own performers.




  • No labels

6 Comments

  1. 1) HasFile  sounds mote like a method name.  I would rename this interface to Fileable.


    2) RuntimeRegionInfo  should be renamed to RegionRuntimeInfo .  RuntimeInfo  should be the suffix of any implementation, otherwise the naming is messy, e.g. RuntimeDiskStoreInfo ; it reads better to say DiskStoreRuntimeInfo.  This is also consistent with ConfigurationManager naming conventions, e.g. CacheConfigurationManager.

    NOTE: I also like Metadata  better than Info, i.e. RuntimeMetadata.


    3) Do not abbreviate names like RegionConfigManager.  Spell it out... RegionConfigurationManager.


    4) Not sure why ConfigurationConverter should be XML specific/partial?  You could define a XmlConfigurationConverter interface for that.  In that manner, then it would be possible to represent different configuration formats, like JSON (e.g. JsonConfigurationConverter).


    5) Seems like the ConfigurationValidator's  responsibilities could simply be part of the ConfigurationManager objects for the configuration.  Not sure why this really requires a separate component.  I'd minimize the API footprint in this case and simply put a validate(..)  method on the ConfigurationManager interface.


    6) Again, RegionConfigRealizer should be named RegionConfigurationRealizer.


    7) OperationPerformer seems sub-standard.  I'd prefer the name OperationProcessor or even OperationExecutor, which is not unlike other interfaces in Apache Geode's API, e.g. ProcessExecutor.

  2. Thanks for the feedback, John. 

    Will consider all the naming change suggestions when we get to work on CMS in the future.

    4) ConfigurationConverter is xml specific. It's used to convert between jaxb objects and the exposed configuration objects.

    5) Sounds like a good simplification. Will consider that too.

  3. Jinmei Liao ,

    Thank you for this write up. It does provide some more clarity regarding how to write one's own. 

    Some feedback:

    1. This is too much text. I feel overwhelmed having navigated to this page. It is too much text and possibly a lack of structure that I could follow.
    2. Can we break up this write up into two separate documents. One for Components (like Region, etc) and one for Operations.
    3. Can we add example code and steps? By providing a more step-like approach all of this information is broken down into manageable pieces. Also providing a simple sample which users can follow will make all of this simpler to digest.
    4. Most to all code referenced is void of comments. Which makes it really hard to understand what it is supposed to do by just reading the code.
    5. `OperationPerformer` needs to be moved from the "internal" domain to "public" domain if this is an interface the we expect users to extend or use. Leaving it in the "internal" domain means that users should not use it, as per our mantra of "internal package code and api can change without notice to consumers"
  4. Thanks for the feedback Udo Kohlmeyer

    1. I had hoped that the table of contents would serve as a structure. Basically to add a end point to manage a cache element, you need to add 4 things, and to add an operation, you need to add 2 things.
    2. I would like to keep all the related information in one place, easy to find. Users would just use the table of contents to navigate to where they want.
    3. Examples sounds good. I had hoped that the link to the github code would be enough as an example for each entity, but looks like it's not.
    4. will consider adding comments in the code.
    5. this a good point. `OperationPerformer` should be public.
  5. Udo Kohlmeyer  Here is a link to a How-to... How does this compare with what you are looking for? Adding REST Cluster Management Operations

    I think this document should really talk about the detail.

  6. Mark Hanson , thank you for the link.

    I think it is a start, but I don't know if it something that we could provide as a "guide" to the public to consume. It feels too complicated.

    I think, anything we write, needs to be structured in a way that makes it easy to consume. We have many committers who have ample technical writing skills and maybe when it comes to these kind of "guides" should receive some form of review from them.

    A purely technical document does not need to be confusing or a chore to read.... I read it, and I struggled to understand 1/2 of what I'm supposed to do, why I need to do it.