Discovery has a REST API that exposes data and some operations to external systems, as is documented here. More recently, we have also added functions within TPL to pull data from targets using their REST API, using the RESful function:
The Atrium CMDB similarly exposes a REST API, as documented here.
I had some early discussions with a couple of customers who asked whether it would be possible to pull data into Discovery from CMDB using the REST API. So I thought I would see how far I could get with it, as a kind of proof-of-concept.
Firstly, I created some data in the CMDB I wanted to retrieve. Fairly arbitrarily, I created some BMC_PhysicalLocation CIs in te Sandbox:
Then I started to look at how I might use the restfulGet() in TPL. Firstly, I needed to decide when to call it. The first pre-requisite was obvious: since you need to tell restfulGet() a target (host):
- The CMDB must have been scanned by Discovery
so that you can pass the function its Host node. This would be simplest to implement if the pattern triggered off the scanning of the CMDB server itself. But a more general case would be where you want to trigger a context-dependent lookup via the REST API on every Host scanned. Is this possible? Although not used very often, yes it is - when running a pattern trigged off some arbitrary Host, you can find the CMDB Host's node like this:
cmdb_host := search(Host where name = 'cmdb.example.com');
Oh, as long as you remember to flip the default Discovery setting:
So, onwards to authentication. It is intended that you create Discovery credentials as normal, and the restful functions select an appropriate one. Unfortunately, the CMDB API uses the JWT mechanism, that Discovery doesn't support. I have logged an improvement (DRUD1-27013: "RestAPI doesn't directly support CMDB Rest API protocol (JSON Web Token)") - if this is important to you please contact support to register your interest.
In order to progress, I had to find some way around this. I found that if I embedded the username/password in pattern (actually configuration options) I could drive the login method directly:
headers := table();
headers['content-type'] := 'application/x-www-form-urlencoded';
rg := discovery.restfulPost(cmdb_host, '', '/api/jwt/login', 'username=%Config.username%&password=%Config.password%',
headers, Config.port, Config.use_http);
authkey := rg.response_body;
Clearly not ideal, but it might just be acceptable as long as a read-only CMDB user is chosen, and access to Discovery is suitably controlled. That let me execute the actual data call, by passing in the previously obtained authkey:
resturl_data := raw '/api/cmdb/v1/instance/BMC.AE.SB.Demo.1/BMC.CORE/BMC_PhysicalLocation?q=%27Priority%27=4&fields=Name%2CShortDescription%2CCity%2CPhysicalPosition%2CCountryCode';
headers := table();
headers['Authorization'] := 'AR-JWT %authkey%';
rg := discovery.restfulGet(cmdb_host, '', resturl_data, headers, Config.port, Config.use_http);
Here, the REST URL Data contains:
- the dataset name ("BMC.AE.SB.Demo.1")
- a URL-encoded query defined in the "q" parameter, limiting Priority to be 4
- a fields parameter to define which fields to return from the CI
Finally, I dumped the data I received in a Detail node (with a little help from the json.decode() function) off the scanned host, just for demo purposes:
Note that there is one CI data missing here, because one doesn't match the Priority value I defined in the query.
Clearly it doesn't do anything useful yet, but it proves that data can be transferred. Further discussions are due with my two customers to look in detail as to whether or not this kind of thing could be useful. If you have some ideas or use cases, please let me know.
Additionally, m'collegue Jean Christophe thinks we can get around the authentication problem by using RSSO's OAuth2 mechanism, but we have not yet been able to find some common time to test this. I hope to update this when we do.