diff --git a/tools/az-prom-rules-converter/README.md b/tools/az-prom-rules-converter/README.md index 1740a90fd..1da800ad5 100644 --- a/tools/az-prom-rules-converter/README.md +++ b/tools/az-prom-rules-converter/README.md @@ -36,3 +36,8 @@ Options: -l, --location Rule group location. -h, --help display help for command ``` + +## usage with pipeline +```bash +Get-Content .\examples\yaml-example1.yml | node az-prom-rules-converter +``` \ No newline at end of file diff --git a/tools/az-prom-rules-converter/dist/cli.js b/tools/az-prom-rules-converter/dist/cli.js index 7c33f5f98..274014929 100644 --- a/tools/az-prom-rules-converter/dist/cli.js +++ b/tools/az-prom-rules-converter/dist/cli.js @@ -24,9 +24,10 @@ program.description('Azure Prometheus rule groups tool'); function yaml2arm(inputPath, options, command) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { - const inputAbsolutePath = path_1.default.resolve(inputPath); - const str = (_a = (yield promises_1.default.readFile(inputAbsolutePath))) === null || _a === void 0 ? void 0 : _a.toString(); - const flowResult = (0, _1.default)(str, options); + const inputStr = inputPath ? + (_a = (yield promises_1.default.readFile(path_1.default.resolve(inputPath)))) === null || _a === void 0 ? void 0 : _a.toString() : + yield readStdin(); + const flowResult = (0, _1.default)(inputStr, options); if (flowResult.success == false) { console.error((_b = flowResult.error) === null || _b === void 0 ? void 0 : _b.title); console.error(JSON.stringify((_c = flowResult.error) === null || _c === void 0 ? void 0 : _c.details, null, 2)); @@ -44,7 +45,7 @@ function yaml2arm(inputPath, options, command) { } program //.command('yaml2arm') .description('Convert Prometheus rules Yaml file to ARM template') - .argument('', 'Input Prometheus rule groups Yaml file path.') + .argument('[input]', 'Input Prometheus rule groups Yaml (or Json) file path.') .option('-amw, --azure-monitor-workspace ', 'Azure monitor workspace id\'s that this rule group is scoped to.') .option('-c, --cluster-name ', 'The cluster name of the rule group evaluation.') .option('-a, --action-group-id ', 'The resource id of the action group to use for alerting rules.') @@ -53,3 +54,19 @@ program //.command('yaml2arm') .option('-l, --location ', 'Rule group location.') .action(yaml2arm); program.parse(); +function readStdin() { + return __awaiter(this, void 0, void 0, function* () { + return new Promise((resolve, reject) => { + let input = ''; + process.stdin.on('data', chunk => { + input += chunk; + }); + process.stdin.on('end', () => { + resolve(input); + }); + process.stdin.on('error', err => { + reject(err); + }); + }); + }); +} diff --git a/tools/az-prom-rules-converter/dist/steps/to-arm-template.js b/tools/az-prom-rules-converter/dist/steps/to-arm-template.js index 7aefe654e..768d1f9ca 100644 --- a/tools/az-prom-rules-converter/dist/steps/to-arm-template.js +++ b/tools/az-prom-rules-converter/dist/steps/to-arm-template.js @@ -68,7 +68,6 @@ const getArmTemplateFormat = (params) => { resources: [] }; ['clusterName', 'actionGroupId', 'azureMonitorWorkspace', 'location'].forEach((paramName) => { - console.log(paramName, params[paramName]); if (params[paramName]) { result.parameters[paramName].defaultValue = params[paramName]; } diff --git a/tools/az-prom-rules-converter/examples/json-example1.json b/tools/az-prom-rules-converter/examples/json-example1.json new file mode 100644 index 000000000..8aba1d96e --- /dev/null +++ b/tools/az-prom-rules-converter/examples/json-example1.json @@ -0,0 +1,18 @@ +{ + "groups": [ + { + "name": "example", + "interval": "2m", + "rules": [ + { + "record": "job:http_inprogress_requests:sum", + "expr": "sum by (job) (http_inprogress_requests)" + }, + { + "alert": "alert name", + "expr": "sum by (job) (http_inprogress_requests)" + } + ] + } + ] +} diff --git a/tools/az-prom-rules-converter/examples/result1.json b/tools/az-prom-rules-converter/examples/result1.json new file mode 100644 index 000000000..7bf35645c --- /dev/null +++ b/tools/az-prom-rules-converter/examples/result1.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "clusterName": { + "type": "string", + "metadata": { + "description": "Cluster name" + } + }, + "actionGroupId": { + "type": "string", + "metadata": { + "description": "Action Group ResourceId" + } + }, + "azureMonitorWorkspace": { + "type": "string", + "metadata": { + "description": "ResourceId of Azure monitor workspace to associate to" + } + } + }, + "variables": {}, + "resources": [ + { + "name": "example", + "type": "Microsoft.AlertsManagement/prometheusRuleGroups", + "apiVersion": "2023-03-01", + "location": "[parameters('location')]", + "properties": { + "interval": "PT2M", + "scopes": ["[parameters('azureMonitorWorkspace')]"], + "clusterName": "[parameters('clusterName')]", + "rules": [ + { + "record": "job:http_inprogress_requests:sum", + "expression": "sum by (job) (http_inprogress_requests)" + }, + { + "severity": 3, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT10M" + }, + "actions": [ + { + "actionGroupId": "[parameters('actionGroupId')]" + } + ], + "alert": "alert name", + "expression": "sum by (job) (http_inprogress_requests)" + } + ] + } + } + ] +} diff --git a/tools/az-prom-rules-converter/test-files/template-example.json b/tools/az-prom-rules-converter/examples/template-example.json similarity index 100% rename from tools/az-prom-rules-converter/test-files/template-example.json rename to tools/az-prom-rules-converter/examples/template-example.json diff --git a/tools/az-prom-rules-converter/test-files/yaml-example.yml b/tools/az-prom-rules-converter/examples/yaml-example1.yml similarity index 100% rename from tools/az-prom-rules-converter/test-files/yaml-example.yml rename to tools/az-prom-rules-converter/examples/yaml-example1.yml diff --git a/tools/az-prom-rules-converter/package.json b/tools/az-prom-rules-converter/package.json index de767dab8..8615086a7 100644 --- a/tools/az-prom-rules-converter/package.json +++ b/tools/az-prom-rules-converter/package.json @@ -1,6 +1,6 @@ { "name": "az-prom-rules-converter", - "version": "1.0.0", + "version": "1.1.0", "description": "", "main": "dist/index.js", "bin": "dist/cli.js", diff --git a/tools/az-prom-rules-converter/src/cli.ts b/tools/az-prom-rules-converter/src/cli.ts index 78afcf465..922e3922d 100644 --- a/tools/az-prom-rules-converter/src/cli.ts +++ b/tools/az-prom-rules-converter/src/cli.ts @@ -12,9 +12,10 @@ program.description('Azure Prometheus rule groups tool'); // program.version(pack.version); async function yaml2arm(inputPath: string, options: any, command: Command) { - const inputAbsolutePath = path.resolve(inputPath); - const str = (await fs.readFile(inputAbsolutePath))?.toString(); - const flowResult: StepResult = toArmTemplateFlow(str, options); + const inputStr = inputPath ? + (await fs.readFile(path.resolve(inputPath)))?.toString() : + await readStdin(); + const flowResult: StepResult = toArmTemplateFlow(inputStr, options); if (flowResult.success == false){ console.error(flowResult.error?.title); @@ -33,7 +34,7 @@ async function yaml2arm(inputPath: string, options: any, command: Command) { program//.command('yaml2arm') .description('Convert Prometheus rules Yaml file to ARM template') - .argument('', 'Input Prometheus rule groups Yaml file path.') + .argument('[input]', 'Input Prometheus rule groups Yaml (or Json) file path.') .option('-amw, --azure-monitor-workspace ', 'Azure monitor workspace id\'s that this rule group is scoped to.') .option('-c, --cluster-name ', 'The cluster name of the rule group evaluation.') .option('-a, --action-group-id ', 'The resource id of the action group to use for alerting rules.') @@ -42,4 +43,23 @@ program//.command('yaml2arm') .option('-l, --location ', 'Rule group location.') .action(yaml2arm); -program.parse(); \ No newline at end of file +program.parse(); + + +async function readStdin(): Promise { + return new Promise((resolve, reject) => { + let input = ''; + + process.stdin.on('data', chunk => { + input += chunk; + }); + + process.stdin.on('end', () => { + resolve(input); + }); + + process.stdin.on('error', err => { + reject(err); + }); + }); +} \ No newline at end of file diff --git a/tools/az-prom-rules-converter/src/index.test.ts b/tools/az-prom-rules-converter/src/index.test.ts new file mode 100644 index 000000000..d61d2c8ec --- /dev/null +++ b/tools/az-prom-rules-converter/src/index.test.ts @@ -0,0 +1,32 @@ +import yamlToArmTemplateFlow from './index'; +import StepResult from './types/step-result'; +import fs from "fs/promises"; + +describe('toArmTemplateFlow example 1', () => { + let expectedResult: any; + + beforeAll(async () => { + expectedResult = JSON.parse( + await fs.readFile("./examples/result1.json", { encoding: "utf-8" }) + ); + }); + + test('Successful flow with valid YAML input', async () => { + await readFileAndRunFlow("./examples/yaml-example1.yml"); + + }); + + test("Successful flow with valid JSON input", async () => { + await readFileAndRunFlow("./examples/json-example1.json"); + }); + + async function readFileAndRunFlow(examplePath : string) { + const options = {}; + const str = (await fs.readFile(examplePath))?.toString(); + const result: StepResult = yamlToArmTemplateFlow(str, options); + + expect(result.success).toBe(true); + expect(result.output).toEqual(expectedResult); + } + +}); \ No newline at end of file diff --git a/tools/az-prom-rules-converter/src/index.ts b/tools/az-prom-rules-converter/src/index.ts index 7bfd74642..684b9efd0 100644 --- a/tools/az-prom-rules-converter/src/index.ts +++ b/tools/az-prom-rules-converter/src/index.ts @@ -1,6 +1,6 @@ import yaml2json from './steps/yaml2json' import StepResult from './types/step-result' -import validatePromSchema from './steps/validate-prom-schemas' +import validatePromSchema from './steps/validate-prom-schemas' import validateArmTemplate from './steps/validate-arm-template' import toArmTemplate from './steps/to-arm-template' import validateInputNotEmpty from './steps/validate-input-not-empty' diff --git a/tools/az-prom-rules-converter/src/steps/to-arm-template.ts b/tools/az-prom-rules-converter/src/steps/to-arm-template.ts index 2faed4679..becf6dabb 100644 --- a/tools/az-prom-rules-converter/src/steps/to-arm-template.ts +++ b/tools/az-prom-rules-converter/src/steps/to-arm-template.ts @@ -66,7 +66,6 @@ const getArmTemplateFormat = (params: any) : any => { resources: [ ] }; ['clusterName', 'actionGroupId', 'azureMonitorWorkspace', 'location'].forEach( (paramName) => { - console.log(paramName, params[paramName]); if (params[paramName]) { result.parameters[paramName].defaultValue = params[paramName]; }