To check all the flows for policy - plugin

Hello Team,

I would like to check if the flow hook policy exists in all the flows of proxy endpoint. I don't want to hardcode the flow names since each customer have their different flows.

@ssvaidyanathan Please check this

I have below but not working

var plugin = {
ruleId: "EX-PE001",
name: "Proxy endpoint - Check for SharedFlow in PostClientFlow",
message:
"Mandatory sharedflow missing in PostClientFlow",
fatal: true,
severity: 2, //0-ignore; 1-warning; 2-error
nodeType: "Endpoint",
enabled: true
}

var onProxyEndpoint = function(ep, cb) {
var hadError = false;


var conditionalflow = false;
var flows = ep.getFlows();
for (var i = 0; i < flows.length; i++) {

var steps = flows[i].getFlowRequest().getSteps();
for (var j = 0; j < steps.length; j++) {
var p = ep.getParent().getPolicyByName(steps[j].getName());
if (step.getName() === "FC-Conditional-Flow-Hook" && p.getType() === "FlowCallout" && p.getName() === "FC-Conditional-Flow-Hook") { //update your FlowCallout policy name here
var sharedFlowName = p.select("//SharedFlowBundle/text()")[0].nodeValue;
if(sharedFlowName === "Conditional-Flow-Hook"){ //Update your sharedflow name here
conditionalflow= true;
break;
}
}
}

}
if (!conditionalflow) {
ep.addMessage({
plugin,
message: "conditionalflow SharedFlow is missing"
});
hadError = true;
}

if (typeof(cb) == 'function') {
cb(null, hadError);
}
};

 

module.exports = {
plugin,
onProxyEndpoint
};

 

0 10 220
10 REPLIES 10

FlowHook is not a policy.. Its an environment configuration.. This is something you cannot be linting  as its not part of the proxy code itself. You will need to make the Mgmt API call and see if the environment has flowhook configured. 

Hello Sai,

 

This requirement is to verify if shared flow is available and attached to all flows.

 

You have helped for similar requirement earlier, where we are checking for the 

FC-ELK-Logger and  shared flow ELK-Logger availability in ONE FLOW only "

PostClientFlow". Please find the below.

 

Now iam checking the shared flow "Conditional-Flow-Hook" availability in all flows by looping through all flows.  But it's not working. My requirement is to check if sharedflow Conditional-Flow-Hook is attached to all flows via flow hook policy or not.

 

--------------

Earlier working code :

var plugin = {

ruleId: "EX-PE001",

name: "Proxy endpoint - Check for SharedFlow in PostClientFlow",

message:

"Mandatory sharedflow missing in PostClientFlow",

fatal: true,

severity: 2, //0-ignore; 1-warning; 2-error 

nodeType: "Endpoint",

enabled: true

}

 

var onProxyEndpoint = function(ep, cb) {

var hadError = false;

//PostClientFlow - check for SharedFlow

var sharedFlowsFoundInPostClientFlow = false;

if (ep.getPostClientFlow()) {

var steps = ep.getPostClientFlow().getFlowResponse().getSteps();

steps.forEach(function(step) {

if (step.getName() && ep.getParent().getPolicies()) {

var p = ep.getParent().getPolicyByName(step.getName());

if (step.getName() === "FC-ELK-Logger" && p.getType() === "FlowCallout" && p.getName() === "FC-ELK-Logger") { //update your FlowCallout policy name here

var sharedFlowName = p.select("//SharedFlowBundle/text()")[0].nodeValue;

if(sharedFlowName === "ELK-Logger"){ //Update your sharedflow name here

sharedFlowsFoundInPostClientFlow= true;

}

}

}

});

}

 

if (!sharedFlowsFoundInPostClientFlow) {

ep.addMessage({

plugin,

message: "PostClientFlow SharedFlow is missing"

});

hadError = true;

}

 

if (typeof(cb) == 'function') {

cb(null, hadError);

}

};

 

module.exports = {

plugin,

onProxyEndpoint

};

 

---------------

 

 

 

Current not working code


var plugin = {
ruleId: "EX-PE001",
name: "Proxy endpoint - Check for SharedFlow in PostClientFlow",
message:
"Mandatory sharedflow missing in PostClientFlow",
fatal: true,
severity: 2, //0-ignore; 1-warning; 2-error
nodeType: "Endpoint",
enabled: true
}

var onProxyEndpoint = function(ep, cb) {
var hadError = false;


var conditionalflow = false;
var flows = ep.getFlows();
for (var i = 0; i < flows.length; i++) {

var steps = flows[i].getFlowRequest().getSteps();
for (var j = 0; j < steps.length; j++) {
var p = ep.getParent().getPolicyByName(steps[j].getName());
if (step.getName() === "FC-Conditional-Flow-Hook" && p.getType() === "FlowCallout" && p.getName() === "FC-Conditional-Flow-Hook") { //update your FlowCallout policy name here
var sharedFlowName = p.select("//SharedFlowBundle/text()")[0].nodeValue;
if(sharedFlowName === "Conditional-Flow-Hook"){ //Update your sharedflow name here
conditionalflow= true;
break;
}
}
}

}
if (!conditionalflow) {
ep.addMessage({
plugin,
message: "conditionalflow SharedFlow is missing"
});
hadError = true;
}

if (typeof(cb) == 'function') {
cb(null, hadError);
}
};

 

module.exports = {
plugin,
onProxyEndpoint
};

 

@ssvaidyanathan Could you please support here

I think you are not following - You certainly have some confusion here or not articulating the ask properly. Let me try and clarify

  • Flowhook is NOT a policy that you can add to your proxy. It's an environment configuration. If you want all your proxy to have that sharedflow, you should just configure that sharedflow as a FlowHook. Please see this link. In that case you dont need to include this in your proxies, Apigee will automatically execute it for every call made to that Apigee environment.
  • Now - if you dont want to use the FlowHook option as mentioned above, your logic of checking if the sharedflow is attached to each flow within the proxy is unnecessary. If it needs to execute before any flow, then you should just add it to the PreFlow once. Thats why we have Preflow. It executes before any other flows. Please read this doc. You should just make sure in your lint plugin, check for that sharedflow in the Preflow. That should be sufficient. You can use the same code logic you wrote for PostClientFlow to check in Preflow as well. 

Hope that clarifies. 

flows.pngflows2_condition.png

 

 

 

Helli @ssvaidyanathan 

I understood the flows. However, like preflow, postflow and postclientflow , we have other flows as well. And each flow have FLOWHOOK attached with sharedflow named "Conditional flow hook". 

I'm attaching the screenshot. Please check the screenshot. As per screenshot, we have flows like "GetOAS", "SendEmail" & "Unknown-resource" other than preflow, postflow and postclientflow.

 

Some other proxies have more than 10 flows other than preflow, postflow and postclientflow. Each flow have respective condition as well, check other screenshot as well.

 

All flows using the flowhook with sharedflow "conditional flow hook".

 

My requirement is not to hardcode the flow names and create a lint plugin such that it checks all the flows to make sure that they need to have flowcallout policy with sharedflow.

 

Hope i'm clear this time. 

 

Regards,

Murthy

 

Unfortunately you are not. You cannot attach a flow hook in proxy. I dont understand why you keep saying its attached to the proxy. What you have is a sharedflow being called using a Flow Callout policy. Now the question I have is - for every conditional flow you have, are you calling the same SharedFlow or are they different for each conditional flow?

My requirement is not to hardcode the flow names and create a lint plugin such that it checks all the flows to make sure that they need to have flowcallout policy with sharedflow.

I think he wants to check for the presence of a FlowCallout Step , within each conditional Flow.   and possibly, that FlowCallout must reference a particular sharedflow.  (Flowhook is irrelevant). 

Am I right Murthy?

 

Yes @dchiesa1 .

@ssvaidyanathan for every conditional flow I have, i'm calling the same SharedFlow 

 

I understand what you are asking but its not best practice to repeat the same set of policies in each Conditional flow. Thats precisely the reason for having a Pre-Flow. Once its added to the Pre-flow, you can just check for that once in your lint plugin. Whatever you are asking can be programmatically done too but I don't think thats logically correct and best practice. Once you move it to the Pre-flow you can make use of the other plugin I helped you with this logic. I am personally not convinced with your approach and hence not in a position to help with the lint plugin

Maybe something like this? 

// EX-EP991.js
// ------------------------------------------------------------------
//
/* jshint esversion:9, node:true, strict:implied */
/* global process */

const plugin = {
        ruleId: "EP991",
        name: "Proxy endpoint - Check for FlowCallout in each Conditional Flow",
        message:  "Mandatory FlowCallout missing in Conditional Flow",
        fatal: true,
        severity: 2, //0-ignore; 1-warning; 2-error
        nodeType: "Endpoint",
        enabled: true
      };

const needle = process.env.sharedflowname || "SF-name-1";

const onProxyEndpoint =
  function(ep, cb) {
    let flagged = false;
    let bundle = ep.getParent();
    let flowsMissingMandatoryFlowCallout =
      ep.getFlows()
      .filter(function(flow) {
        let steps = flow.getFlowRequest().getSteps();
        let found = steps && steps.find(function(step) {
              let policyName = step.getName();
              let policy = bundle.getPolicyByName(policyName);
              let isFlowCallout = policy && policy.getType() == "FlowCallout";
              let texts = isFlowCallout && policy.select("//SharedFlowBundle/text()");
              let sharedFlowName = texts && (texts.length == 1) && texts[0] && texts[0].nodeValue;
              return sharedFlowName && (sharedFlowName == needle); // found
            });
        return !found;
      });

    flowsMissingMandatoryFlowCallout.forEach( f => {
      ep.addMessage({
        plugin,
        line: f.element.lineNumber,
        column: f.element.columnNumber,
        message: `Direct FlowCallout to mandatory sharedflow (${needle}) is missing in Conditional Flow`
      });
      flagged = true;
    });

    if (typeof(cb) == 'function') {
      cb(null, flagged);
    }
  };


module.exports = {
  plugin,
  onProxyEndpoint
};

The way it works: 

for each proxy endpoint in a bundle:

find (filter) any of the conditional flows in that endpoint that do not satisfy this requirement:

there must be a requestflow, and there must be a step, that is a FlowCallout, and that FlowCallout must refer to a particular sharedflow. 

If there are any conditional flows that do not satisfy that requirement, flag them with an error message on the endpoint.

 

example run & output: 

$ sharedflowname=SF-name-1 node ./cli.js -x ./externalPlugins/ -s ~/dev/bundle1/apiproxy/  | jq . | more
[
  {
    "filePath": "/apiproxy",
    "errorCount": 0,
    "warningCount": 0,
    "fixableErrorCount": 0,
    "fixableWarningCount": 0,
    "messages": []
  },
  {
    "filePath": "/apiproxy/proxies/endpoint1.xml",
    "errorCount": 2,
    "warningCount": 1,
    "fixableErrorCount": 0,
    "fixableWarningCount": 0,
    "messages": [
      {
        "line": 54,
        "column": 5,
        "message": "Direct FlowCallout to mandatory sharedflow (SF-name-1) is missing in Conditional Flow",
        "ruleId": "EP991",
        "severity": 2,
        "nodeType": "Endpoint"
      },
      {
        "line": 67,
        "column": 5,
        "message": "Direct FlowCallout to mandatory sharedflow (SF-name-1) is missing in Conditional Flow",
        "ruleId": "EP991",
        "severity": 2,
        "nodeType": "Endpoint"
      },
      ...

ps: Sai and I don't write plugins as a side gig.  If this example isn't what you want, I'm hoping YOU can adjust it to fit your needs!