Automating MuleSoft Anypoint Platform Management

Recently, I’ve found an enterprise client that is planning for hundreds of API applications and I’ve been consulted to provide them DevOps support. Currently, they are managing API’s at anypoint.mulesoft.com by hand. And, someone in the infrastructure group has figured out, with the help of the development groups, how to manage Anypoint along with the deployment of artifacts to their Mule clusters.

The newly appointed C4E evangelist there has me working on key difficulties where I’ll automate Anypoint platform operations and data interactions with development and infrastructure using their software repositories and Atlassian Bamboo.

We (the new C4E team) checked around the shop so-to-speak to find a robust scripting language to write this automation code. I proposed Ruby and they countered with Javascript. Perfect! I was pleased because Bamboo has a Node/NPM plugin that will allow us to use a Node environment and coding/dependency infrastructure on the Bamboo server from our build and deploy plans. This is fantastic!

The second question was whether we use the anypoint-cli tool or the REST APIs. The right answer was both. The REST APIs are very well documented but the resources are not complete. And, another developer on our team is focused on deployment to the Mule runtime infrastructure and he’s using Node to run the anypoint-cli tool from Bamboo. My focus currently has been:

  1. Create a client application and request access of existing published API assets in Exchange.
  2. Create an API instance in API Manager and retrieve a new appId to be given to development for their auto-discovery element in their Mule project configuration.

I started the first item with the realization that every operation (REST) would be an async javascript function that returns a <Promise>. I initially used the npm package “node-fetch”. This served me well until I moved my code onto the client network. They have a proxy server in place and I switched packages to “request-promise”. This package let’s me specify the proxy in the call options and also handles the HTTPS handshake that occurs on the other side of the proxy.

My first asynchronous function would be to get a bearer token. Here’s a look at how I did this.

/**
 * This asynchronous function is used to call the Anypoint Platform API for administration and management
 *
 * The function makes an HTTP POST to:
 *    https://anypoint.mulesoft.com/accounts/login
 *
 * ... all for the service account user (see constants.js).
 *
 * @author David L. Whitehurst.
 * @since  1.0.0
 *
 * @return {Promise} - returns a Promise, resolves to a string e.g. 5b2f78c9-3c43-4c24-9b22-8139d4ccc4fb.
 */
async function getToken() {
    const options = {
        method: 'POST',
        uri: 'https://anypoint.mulesoft.com/accounts/login',
        //proxy: 'http://proxy.corp.fin:8080',
        body: constants.credentials,
        headers: { 'Content-Type': 'application/json' },
        json: true,
    }

    const data = await request(options)
        .then (function (response) {
            // Request was successful, use the response object at will
            return response;
        })
        .catch (function(err) {
            console.log(err);
            return err;
        });

    return data.access_token;
}

The token is the first thing you need to do before you can call any other anypoint API. For some resource paths, you’ll need an organizationId for your operations. Here’s an example of how you asynchronously get the token and then use it with the getOrganizationId asynchronous call.

    const authtoken = await apiService.getToken();
    console.log('token:' + authtoken);    
    const orgId = await apiService.getOrganizationId(authtoken);
    console.log('orgId:' + orgId);

The constant or final variable authtoken is not filled or set until the getToken() function has completed. Asynchronous functions will immediately return a Promise and if the await is not used, the log statement in the console would read “token: undefined”. The await statement in front of the function allows the Promise to resolve() or reject().

As a reminder of my number 1 task, “Create a client application and request access of existing published API assets in Exchange.” To do this we’ll inspect my async function and discuss the input arguments.

    const contract = await apiService.createContractRequestingAccess(authtoken, apiId, versionId, appId);
    console.log('clientId:' + contract[0]);
    console.log('clientSecret:' + contract[1]);

The key function here needed to return a simple array with the credentials our client application needs to connect to and use the published API asset. The function requires the bearer token (discussed earlier), the apiId, versionId, and appId. These data points are not immediately available. We need to call other functions before we can do the task at hand. Here’s a chain of asynchronous calls to achieve our task.

    const authtoken = await apiService.getToken();
    console.log('token:' + authtoken);

    const orgId = await apiService.getOrganizationId(authtoken);
    console.log('orgId:' + orgId);

    const defaultEnvId = await apiService.getDefaultEnvironmentId(authtoken);
    console.log('envId:' + defaultEnvId);

    const created = await apiService.createClientApplication(authtoken, 'emp-xapi');
    console.log(created);

    const appId = await apiService.getApplicationId(authtoken, 'emp-xapi');
    console.log('appId:' + appId);

    const apiId = await apiService.getApiId(authtoken, 'emp-sapi');
    console.log('apiId:' + apiId);

    const versionId = await apiService.getVersionId(authtoken, apiId, 'v1');
    console.log('versionId:' + versionId);

    const contract = await apiService.createContractRequestingAccess(authtoken, apiId, versionId, appId);
    console.log('clientId:' + contract[0]);
    console.log('clientSecret:' + contract[1]);

 

These functions will probably be ultimately added to a single function call.

I’m not going to describe the second task, but I am going to say that the key here was finding the right npm package for the REST calls and understanding how to work with the asynchronous functions.

Leave a Comment

Your email address will not be published. Required fields are marked *