@adobe/aio-cli-plugin-api-mesh 5.4.0-beta.0 → 5.4.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
- package/src/commands/api-mesh/__tests__/get-log-forwarding-errors.test.js +225 -0
- package/src/commands/api-mesh/config/delete/log-forwarding.js +2 -0
- package/src/commands/api-mesh/config/get/log-forwarding/errors.js +166 -0
- package/src/commands/api-mesh/config/get/{log-forwarding.js → log-forwarding/index.js} +12 -5
- package/src/commands/api-mesh/config/index.js +5 -3
- package/src/commands/api-mesh/config/set/log-forwarding.js +2 -0
- package/src/commands/api-mesh/init.js +4 -1
- package/src/lib/smsClient.js +42 -0
- package/src/templates/deployWorkflow.yaml +38 -8
- package/src/templates/loadTestWorkflow.yaml +2 -2
- package/src/templates/readme.md +23 -0
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"5.4.0-beta.0","commands":{"api-mesh":{"id":"api-mesh","description":"Create, run, test, and deploy API Mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{},"args":[]},"api-mesh:create":{"id":"api-mesh:create","description":"Create a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"secrets":{"name":"secrets","type":"option","char":"s","description":"Path to secrets file","default":false}},"args":[{"name":"file"}]},"api-mesh:delete":{"id":"api-mesh:delete","description":"Delete the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false}},"args":[]},"api-mesh:describe":{"id":"api-mesh:describe","description":"Get details of a mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:get":{"id":"api-mesh:get","description":"Get the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[{"name":"file"}]},"api-mesh:init":{"id":"api-mesh:init","description":"This command will create a workspace where you can organise your API mesh configuration and other files","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[{"description":"API mesh workspace init","command":"aio api-mesh init commerce-mesh"},{"description":"API mesh workspace init with flags","command":"aio api-mesh init commerce-mesh --path ./mesh_projects/test_mesh --git y --packageManager yarn"}],"flags":{"path":{"name":"path","type":"option","char":"p","default":"."},"packageManager":{"name":"packageManager","type":"option","char":"m","options":["npm","yarn"]},"git":{"name":"git","type":"option","char":"g","options":["y","n"]}},"args":[{"name":"projectName","description":"Project name","required":true}]},"api-mesh:log-get-bulk":{"id":"api-mesh:log-get-bulk","description":"Download all mesh logs for a selected time period.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"startTime":{"name":"startTime","type":"option","description":"Start time for the logs in UTC"},"endTime":{"name":"endTime","type":"option","description":"End time for the logs in UTC"},"filename":{"name":"filename","type":"option","description":"Path to the output file for logs","required":true},"past":{"name":"past","type":"option","description":"Past time window in minutes"}},"args":[]},"api-mesh:log-get":{"id":"api-mesh:log-get","description":"Get the Log of a given mesh by RayId","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[{"name":"rayId","description":"Fetch a single log by rayID","required":true}]},"api-mesh:log-list":{"id":"api-mesh:log-list","description":"Get recent logs of requests made to the API Mesh.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"filename":{"name":"filename","type":"option","description":"Name of CSV file to export the recent logs to"}},"args":[]},"api-mesh:run":{"id":"api-mesh:run","description":"Run a local development server that builds and compiles a mesh locally","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[],"flags":{"port":{"name":"port","type":"option","char":"p","description":"Port number for the local dev server","default":5000},"inspectPort":{"name":"inspectPort","type":"option","char":"i","description":"Port number for the local dev server inspector","default":9229},"debug":{"name":"debug","type":"boolean","description":"Enable debugging mode","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"select":{"name":"select","type":"boolean","description":"Retrieve existing artifacts from the mesh","allowNo":false},"secrets":{"name":"secrets","type":"option","char":"s","description":"Path to secrets file","default":false}},"args":[{"name":"file","description":"Mesh File"}]},"api-mesh:status":{"id":"api-mesh:status","description":"Get a mesh status with a given meshid.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:update":{"id":"api-mesh:update","description":"Update a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"secrets":{"name":"secrets","type":"option","char":"s","description":"Path to secrets file","default":false}},"args":[{"name":"file"}]},"api-mesh:cache:purge":{"id":"api-mesh:cache:purge","description":"Cache purge for a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"all":{"name":"all","type":"boolean","char":"a","description":"Purge all cache. CLI will purge all cache data.","required":true,"allowNo":false}},"args":[]},"api-mesh:config":{"id":"api-mesh:config","description":"Manage the configuration for API Mesh.\n\nThe 'config' command includes the following options:\n- set: Set log forwarding details for a given mesh.\n- get: Retrieve log forwarding details for a given mesh.\n- delete: Delete log forwarding details for a given mesh.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{},"args":[]},"api-mesh:source:discover":{"id":"api-mesh:source:discover","description":"Return the list of avaliable sources","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm install action prompt. CLI will not check ask user to install source.","allowNo":false}},"args":[]},"api-mesh:source:get":{"id":"api-mesh:source:get","description":"Command returns the content of a specific source.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:get -s=<version>@<source_name>","$ aio api-mesh:source:get -s<source_name>","$ aio api-mesh:source:get -m"],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm print action prompt. CLI will not check ask user to print source.","allowNo":false},"source":{"name":"source","type":"option","char":"s","description":"Source name"},"multiple":{"name":"multiple","type":"boolean","char":"m","description":"Select multiple sources","allowNo":false}},"args":[]},"api-mesh:source:install":{"id":"api-mesh:source:install","description":"Command to install the source to your API mesh.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:install <version>@<source_name>","$ aio api-mesh:source:install <source_name> -v <variable_name>=<variable_value>","$ aio api-mesh:source:install <source_name> -f <path_to_variables_file>"],"flags":{"source":{"name":"source","type":"option","char":"s","description":"Source name"},"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm override action prompt. CLI will not check ask user to override source.","allowNo":false},"variable":{"name":"variable","type":"option","char":"v","description":"Variables required for the source"},"variable-file":{"name":"variable-file","type":"option","char":"f","description":"Variables file path"},"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[{"name":"source"}]},"api-mesh:config:delete:log-forwarding":{"id":"api-mesh:config:delete:log-forwarding","description":"Delete log forwarding details for a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false}},"args":[]},"api-mesh:config:get:log-forwarding":{"id":"api-mesh:config:get:log-forwarding","description":"Get log forwarding details for a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[]},"api-mesh:config:set:log-forwarding":{"id":"api-mesh:config:set:log-forwarding","description":"Sets the log forwarding destination for API mesh. \n- Select a log forwarding destination - Choose from available options (for example, New Relic).\n- Enter the base URI - Provide the URI for the log forwarding service. Ensure it includes the protocol (for example, if the hosted region of the New Relic account is the U.S, the base URI could be 'https://log-api.newrelic.com/log/v1').\n- Enter the license key - Provide the INGEST-LICENSE API key type.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[]}}}
|
|
1
|
+
{"version":"5.4.0-beta.2","commands":{"api-mesh":{"id":"api-mesh","description":"Create, run, test, and deploy API Mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{},"args":[]},"api-mesh:create":{"id":"api-mesh:create","description":"Create a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"secrets":{"name":"secrets","type":"option","char":"s","description":"Path to secrets file","default":false}},"args":[{"name":"file"}]},"api-mesh:delete":{"id":"api-mesh:delete","description":"Delete the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false}},"args":[]},"api-mesh:describe":{"id":"api-mesh:describe","description":"Get details of a mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:get":{"id":"api-mesh:get","description":"Get the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[{"name":"file"}]},"api-mesh:init":{"id":"api-mesh:init","description":"This command will create a workspace where you can organise your API mesh configuration and other files","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[{"description":"API mesh workspace init","command":"aio api-mesh init commerce-mesh"},{"description":"API mesh workspace init with flags","command":"aio api-mesh init commerce-mesh --path ./mesh_projects/test_mesh --git y --packageManager yarn"}],"flags":{"path":{"name":"path","type":"option","char":"p","default":"."},"packageManager":{"name":"packageManager","type":"option","char":"m","options":["npm","yarn"]},"git":{"name":"git","type":"option","char":"g","options":["y","n"]}},"args":[{"name":"projectName","description":"Project name","required":true}]},"api-mesh:log-get-bulk":{"id":"api-mesh:log-get-bulk","description":"Download all mesh logs for a selected time period.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"startTime":{"name":"startTime","type":"option","description":"Start time for the logs in UTC"},"endTime":{"name":"endTime","type":"option","description":"End time for the logs in UTC"},"filename":{"name":"filename","type":"option","description":"Path to the output file for logs","required":true},"past":{"name":"past","type":"option","description":"Past time window in minutes"}},"args":[]},"api-mesh:log-get":{"id":"api-mesh:log-get","description":"Get the Log of a given mesh by RayId","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[{"name":"rayId","description":"Fetch a single log by rayID","required":true}]},"api-mesh:log-list":{"id":"api-mesh:log-list","description":"Get recent logs of requests made to the API Mesh.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"filename":{"name":"filename","type":"option","description":"Name of CSV file to export the recent logs to"}},"args":[]},"api-mesh:run":{"id":"api-mesh:run","description":"Run a local development server that builds and compiles a mesh locally","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[],"flags":{"port":{"name":"port","type":"option","char":"p","description":"Port number for the local dev server","default":5000},"inspectPort":{"name":"inspectPort","type":"option","char":"i","description":"Port number for the local dev server inspector","default":9229},"debug":{"name":"debug","type":"boolean","description":"Enable debugging mode","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"select":{"name":"select","type":"boolean","description":"Retrieve existing artifacts from the mesh","allowNo":false},"secrets":{"name":"secrets","type":"option","char":"s","description":"Path to secrets file","default":false}},"args":[{"name":"file","description":"Mesh File"}]},"api-mesh:status":{"id":"api-mesh:status","description":"Get a mesh status with a given meshid.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:update":{"id":"api-mesh:update","description":"Update a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"secrets":{"name":"secrets","type":"option","char":"s","description":"Path to secrets file","default":false}},"args":[{"name":"file"}]},"api-mesh:cache:purge":{"id":"api-mesh:cache:purge","description":"Cache purge for a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"all":{"name":"all","type":"boolean","char":"a","description":"Purge all cache. CLI will purge all cache data.","required":true,"allowNo":false}},"args":[]},"api-mesh:config":{"id":"api-mesh:config","description":"The 'config' command includes the following options:\n- set: Set log forwarding details for a given mesh.\n- get: Retrieve log forwarding details for a given mesh.\n- delete: Delete log forwarding details for a given mesh.","usage":"api-mesh:config [COMMAND]","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{},"args":[]},"api-mesh:source:discover":{"id":"api-mesh:source:discover","description":"Return the list of avaliable sources","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm install action prompt. CLI will not check ask user to install source.","allowNo":false}},"args":[]},"api-mesh:source:get":{"id":"api-mesh:source:get","description":"Command returns the content of a specific source.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:get -s=<version>@<source_name>","$ aio api-mesh:source:get -s<source_name>","$ aio api-mesh:source:get -m"],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm print action prompt. CLI will not check ask user to print source.","allowNo":false},"source":{"name":"source","type":"option","char":"s","description":"Source name"},"multiple":{"name":"multiple","type":"boolean","char":"m","description":"Select multiple sources","allowNo":false}},"args":[]},"api-mesh:source:install":{"id":"api-mesh:source:install","description":"Command to install the source to your API mesh.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:install <version>@<source_name>","$ aio api-mesh:source:install <source_name> -v <variable_name>=<variable_value>","$ aio api-mesh:source:install <source_name> -f <path_to_variables_file>"],"flags":{"source":{"name":"source","type":"option","char":"s","description":"Source name"},"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm override action prompt. CLI will not check ask user to override source.","allowNo":false},"variable":{"name":"variable","type":"option","char":"v","description":"Variables required for the source"},"variable-file":{"name":"variable-file","type":"option","char":"f","description":"Variables file path"},"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[{"name":"source"}]},"api-mesh:config:delete:log-forwarding":{"id":"api-mesh:config:delete:log-forwarding","description":"Delete log forwarding details for a given mesh","usage":"api-mesh:config:delete:log-forwarding","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false}},"args":[]},"api-mesh:config:set:log-forwarding":{"id":"api-mesh:config:set:log-forwarding","description":"Sets the log forwarding destination for API mesh. \n- Select a log forwarding destination - Choose from available options (for example, New Relic).\n- Enter the base URI - Provide the URI for the log forwarding service. Ensure it includes the protocol (for example, if the hosted region of the New Relic account is the U.S, the base URI could be 'https://log-api.newrelic.com/log/v1').\n- Enter the license key - Provide the INGEST-LICENSE API key type.","usage":"api-mesh:config:set:log-forwarding","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[]},"api-mesh:config:get:log-forwarding:errors":{"id":"api-mesh:config:get:log-forwarding:errors","description":"Get log forwarding errors for the mesh.","usage":"api-mesh:config:get:log-forwarding:errors","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"filename":{"name":"filename","type":"option","description":"Name of CSV file to export the recent logs to"}},"args":[]},"api-mesh:config:get:log-forwarding":{"id":"api-mesh:config:get:log-forwarding","description":"Get log forwarding details and error logs for a specified mesh.\n\n-The 'log-forwarding' command includes the following options:\n\n- api-mesh:config:get:log-forwarding : Retrieve log forwarding details for a given mesh.\n- api-mesh:config:get:log-forwarding:errors : Download log forwarding error logs for a selected time period.","usage":"api-mesh:config:get:log-forwarding","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[]}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/aio-cli-plugin-api-mesh",
|
|
3
|
-
"version": "5.4.0-beta.
|
|
3
|
+
"version": "5.4.0-beta.2",
|
|
4
4
|
"description": "Adobe I/O CLI plugin to develop and manage API mesh sources",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oclif-plugin"
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"version": "oclif-dev readme && git add README.md"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@adobe-apimesh/mesh-builder": "2.
|
|
41
|
+
"@adobe-apimesh/mesh-builder": "2.2.0",
|
|
42
42
|
"@adobe/aio-cli-lib-console": "^5.0.0",
|
|
43
43
|
"@adobe/aio-lib-core-config": "^5.0.0",
|
|
44
44
|
"@adobe/aio-lib-core-logging": "^3.0.0",
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2021 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
8
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
9
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
|
+
governing permissions and limitations under the License.
|
|
11
|
+
*/
|
|
12
|
+
jest.mock('fs');
|
|
13
|
+
jest.mock('axios');
|
|
14
|
+
|
|
15
|
+
jest.mock('../../../helpers', () => ({
|
|
16
|
+
initSdk: jest.fn().mockResolvedValue({}),
|
|
17
|
+
initRequestId: jest.fn().mockResolvedValue({}),
|
|
18
|
+
promptConfirm: jest.fn().mockResolvedValue(true),
|
|
19
|
+
}));
|
|
20
|
+
jest.mock('../../../lib/smsClient');
|
|
21
|
+
jest.mock('../../../classes/logger');
|
|
22
|
+
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
const GetLogForwardingErrorsCommand = require('../config/get/log-forwarding/errors');
|
|
26
|
+
const { initSdk, promptConfirm } = require('../../../helpers');
|
|
27
|
+
const { getMeshId, getLogForwardingErrors } = require('../../../lib/smsClient');
|
|
28
|
+
|
|
29
|
+
describe('GetLogForwardingErrorsCommand', () => {
|
|
30
|
+
let parseSpy;
|
|
31
|
+
let logSpy;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
logSpy = jest
|
|
35
|
+
.spyOn(GetLogForwardingErrorsCommand.prototype, 'log')
|
|
36
|
+
.mockImplementation(() => {});
|
|
37
|
+
parseSpy = jest
|
|
38
|
+
.spyOn(GetLogForwardingErrorsCommand.prototype, 'parse')
|
|
39
|
+
.mockResolvedValue({ flags: { filename: undefined, ignoreCache: false } });
|
|
40
|
+
jest.spyOn(path, 'extname').mockReturnValue('.csv');
|
|
41
|
+
jest.spyOn(path, 'resolve').mockImplementation((...args) => args.join('/'));
|
|
42
|
+
initSdk.mockResolvedValue({
|
|
43
|
+
imsOrgId: 'orgId',
|
|
44
|
+
imsOrgCode: 'orgCode',
|
|
45
|
+
projectId: 'projectId',
|
|
46
|
+
workspaceId: 'workspaceId',
|
|
47
|
+
workspaceName: 'workspaceName',
|
|
48
|
+
});
|
|
49
|
+
getMeshId.mockResolvedValue('meshId');
|
|
50
|
+
getLogForwardingErrors.mockResolvedValue({
|
|
51
|
+
presignedUrls: ['http://example.com/error1', 'http://example.com/error2'],
|
|
52
|
+
totalSize: 1024,
|
|
53
|
+
});
|
|
54
|
+
jest
|
|
55
|
+
.spyOn(GetLogForwardingErrorsCommand.prototype, 'downloadFileContent')
|
|
56
|
+
.mockImplementation(() => createMockStream(mockLogData));
|
|
57
|
+
fs.existsSync.mockReturnValue(false);
|
|
58
|
+
fs.writeFileSync.mockImplementation(() => {});
|
|
59
|
+
fs.statSync.mockReturnValue({ size: 0 });
|
|
60
|
+
path.extname = jest.fn().mockReturnValue('.csv');
|
|
61
|
+
path.resolve = jest.fn().mockImplementation((...args) => args.join('/'));
|
|
62
|
+
promptConfirm.mockResolvedValue(true);
|
|
63
|
+
global.requestId = 'dummy_request_id';
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
afterEach(() => {
|
|
67
|
+
jest.clearAllMocks();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('prints log lines to console when no filename provided', async () => {
|
|
71
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
72
|
+
await command.run();
|
|
73
|
+
// Accept log message with or without leading newline
|
|
74
|
+
const logCalls = logSpy.mock.calls.map(call => call[0]);
|
|
75
|
+
const found = logCalls.some(
|
|
76
|
+
line => line.trim() === 'Successfully fetched log forwarding errors.',
|
|
77
|
+
);
|
|
78
|
+
expect(found).toBe(true);
|
|
79
|
+
const logLines = logCalls.filter(line => line.startsWith('> '));
|
|
80
|
+
expect(logLines.length).toBe(6); // 3 lines per file * 2 files
|
|
81
|
+
expect(logLines[0]).toBe('> Error log line 1');
|
|
82
|
+
expect(logLines[1]).toBe('> Error log line 2');
|
|
83
|
+
expect(logLines[2]).toBe('> Error log line 3');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('writes to file when filename provided and user confirms', async () => {
|
|
87
|
+
parseSpy.mockResolvedValueOnce({ flags: { filename: 'test.csv', ignoreCache: false } });
|
|
88
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
89
|
+
await command.run();
|
|
90
|
+
expect(promptConfirm).toHaveBeenCalledWith(
|
|
91
|
+
'The expected file size is 1.00 KB. Confirm test.csv download? (y/n)',
|
|
92
|
+
);
|
|
93
|
+
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
|
94
|
+
expect.stringContaining('test.csv'),
|
|
95
|
+
expect.stringContaining('Error log line 1'),
|
|
96
|
+
'utf8',
|
|
97
|
+
);
|
|
98
|
+
expect(logSpy).toHaveBeenCalledWith(
|
|
99
|
+
'Successfully downloaded the log forwarding error logs to test.csv',
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('does not write file when user declines confirmation', async () => {
|
|
104
|
+
parseSpy.mockResolvedValueOnce({ flags: { filename: 'test.csv', ignoreCache: false } });
|
|
105
|
+
promptConfirm.mockResolvedValueOnce(false);
|
|
106
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
107
|
+
await command.run();
|
|
108
|
+
expect(fs.writeFileSync).toHaveBeenCalledTimes(1); // Only the initial empty file creation
|
|
109
|
+
expect(fs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('test.csv'), '');
|
|
110
|
+
expect(logSpy).toHaveBeenCalledWith('Log forwarding errors file not downloaded.');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('throws error for invalid file extension', async () => {
|
|
114
|
+
parseSpy.mockResolvedValueOnce({ flags: { filename: 'test.txt', ignoreCache: false } });
|
|
115
|
+
path.extname.mockReturnValue('.txt');
|
|
116
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
117
|
+
await expect(command.run()).rejects.toThrow(
|
|
118
|
+
'Invalid file type. Provide a filename with a .csv extension.',
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('throws error if existing file is not empty', async () => {
|
|
123
|
+
parseSpy.mockResolvedValueOnce({ flags: { filename: 'test.csv', ignoreCache: false } });
|
|
124
|
+
fs.existsSync.mockReturnValue(true);
|
|
125
|
+
fs.statSync.mockReturnValue({ size: 100 });
|
|
126
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
127
|
+
await expect(command.run()).rejects.toThrow('Make sure the file: test.csv is empty');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('creates empty file if it does not exist', async () => {
|
|
131
|
+
parseSpy.mockResolvedValueOnce({ flags: { filename: 'test.csv', ignoreCache: false } });
|
|
132
|
+
fs.existsSync.mockReturnValue(false);
|
|
133
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
134
|
+
await command.run();
|
|
135
|
+
expect(fs.writeFileSync).toHaveBeenCalledWith(expect.stringContaining('test.csv'), '');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test('throws error if no presignedUrls returned', async () => {
|
|
139
|
+
getLogForwardingErrors.mockResolvedValueOnce({ presignedUrls: [], totalSize: 0 });
|
|
140
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
141
|
+
await expect(command.run()).rejects.toThrow(
|
|
142
|
+
'No log forwarding errors found for the configured destination.',
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('throws error if totalSize is 0', async () => {
|
|
147
|
+
getLogForwardingErrors.mockResolvedValueOnce({
|
|
148
|
+
presignedUrls: ['http://example.com/error1'],
|
|
149
|
+
totalSize: 0,
|
|
150
|
+
});
|
|
151
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
152
|
+
await expect(command.run()).rejects.toThrow(
|
|
153
|
+
'No log forwarding error logs available for the configured destination.',
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('throws error if meshId is not found', async () => {
|
|
158
|
+
getMeshId.mockResolvedValueOnce(null);
|
|
159
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
160
|
+
await expect(command.run()).rejects.toThrow(
|
|
161
|
+
'Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id',
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test('throws error if getMeshId throws', async () => {
|
|
166
|
+
getMeshId.mockImplementationOnce(() => {
|
|
167
|
+
throw new Error('fail mesh');
|
|
168
|
+
});
|
|
169
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
170
|
+
await expect(command.run()).rejects.toThrow(
|
|
171
|
+
'Unable to get mesh ID. Please check the details and try again. RequestId: dummy_request_id',
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('handles download failure gracefully', async () => {
|
|
176
|
+
jest
|
|
177
|
+
.spyOn(GetLogForwardingErrorsCommand.prototype, 'downloadFileContent')
|
|
178
|
+
.mockRejectedValueOnce(new Error('Download failed'));
|
|
179
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
180
|
+
await command.run();
|
|
181
|
+
const logCalls = logSpy.mock.calls.map(call => call[0]);
|
|
182
|
+
const found = logCalls.some(line =>
|
|
183
|
+
line.includes('Failed to download or process log file: Download failed'),
|
|
184
|
+
);
|
|
185
|
+
expect(found).toBe(true);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('filters out empty lines from content', async () => {
|
|
189
|
+
const mockDataWithEmptyLines = `Line 1\n\nLine 2\n\n\nLine 3\n`;
|
|
190
|
+
jest
|
|
191
|
+
.spyOn(GetLogForwardingErrorsCommand.prototype, 'downloadFileContent')
|
|
192
|
+
.mockImplementation(() => createMockStream(mockDataWithEmptyLines));
|
|
193
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
194
|
+
await command.run();
|
|
195
|
+
const logCalls = logSpy.mock.calls.map(call => call[0]);
|
|
196
|
+
const logLines = logCalls.filter(line => line.startsWith('> '));
|
|
197
|
+
expect(logLines.length).toBe(6); // 3 non-empty lines per file * 2 files
|
|
198
|
+
expect(logLines[0]).toBe('> Line 1');
|
|
199
|
+
expect(logLines[1]).toBe('> Line 2');
|
|
200
|
+
expect(logLines[2]).toBe('> Line 3');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('calls getLogForwardingErrors with correct parameters', async () => {
|
|
204
|
+
const command = new GetLogForwardingErrorsCommand([], {});
|
|
205
|
+
await command.run();
|
|
206
|
+
expect(getLogForwardingErrors).toHaveBeenCalledWith(
|
|
207
|
+
'orgCode',
|
|
208
|
+
'projectId',
|
|
209
|
+
'workspaceId',
|
|
210
|
+
'meshId',
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const mockLogData = `Error log line 1\nError log line 2\n\nError log line 3`;
|
|
216
|
+
|
|
217
|
+
function createMockStream(data) {
|
|
218
|
+
const { Readable } = require('stream');
|
|
219
|
+
const stream = new Readable({
|
|
220
|
+
read() {},
|
|
221
|
+
});
|
|
222
|
+
stream.push(data);
|
|
223
|
+
stream.push(null);
|
|
224
|
+
return stream;
|
|
225
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2021 Adobe. All rights reserved.
|
|
3
|
+
This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License. You may obtain a copy
|
|
5
|
+
of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
Unless required by applicable law or agreed to in writing, software distributed under
|
|
7
|
+
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
|
8
|
+
OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
|
+
governing permissions and limitations under the License.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { Command } = require('@oclif/core');
|
|
13
|
+
const { initSdk, promptConfirm } = require('../../../../../helpers');
|
|
14
|
+
const { getMeshId, getLogForwardingErrors } = require('../../../../../lib/smsClient');
|
|
15
|
+
const logger = require('../../../../../classes/logger');
|
|
16
|
+
const axios = require('axios');
|
|
17
|
+
const { ignoreCacheFlag, fileNameFlag } = require('../../../../../utils');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
require('dotenv').config();
|
|
22
|
+
|
|
23
|
+
class GetLogForwardingErrorsCommand extends Command {
|
|
24
|
+
static flags = {
|
|
25
|
+
ignoreCache: ignoreCacheFlag,
|
|
26
|
+
filename: fileNameFlag,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
static usage = 'api-mesh:config:get:log-forwarding:errors';
|
|
30
|
+
|
|
31
|
+
async run() {
|
|
32
|
+
logger.info(`RequestId: ${global.requestId}`);
|
|
33
|
+
|
|
34
|
+
const { flags } = await this.parse(GetLogForwardingErrorsCommand);
|
|
35
|
+
|
|
36
|
+
const { ignoreCache, filename } = await flags;
|
|
37
|
+
|
|
38
|
+
logger.info('Calling initSdk...');
|
|
39
|
+
|
|
40
|
+
const { imsOrgCode, projectId, workspaceId } = await initSdk({ ignoreCache });
|
|
41
|
+
|
|
42
|
+
// Retrieve meshId
|
|
43
|
+
let meshId = '';
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
meshId = await getMeshId(imsOrgCode, projectId, workspaceId, meshId);
|
|
47
|
+
if (!meshId) {
|
|
48
|
+
throw new Error('MeshIdNotFound');
|
|
49
|
+
}
|
|
50
|
+
} catch (err) {
|
|
51
|
+
this.error(
|
|
52
|
+
`Unable to get mesh ID. Please check the details and try again. RequestId: ${global.requestId}`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// fetch log forwarding errors presigned URLs
|
|
57
|
+
const { presignedUrls, totalSize } = await getLogForwardingErrors(
|
|
58
|
+
imsOrgCode,
|
|
59
|
+
projectId,
|
|
60
|
+
workspaceId,
|
|
61
|
+
meshId,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// If presigned URLs are not found, throw error saying that no log forwarding errors are found
|
|
65
|
+
if (!presignedUrls || presignedUrls.length === 0) {
|
|
66
|
+
this.error(
|
|
67
|
+
`No log forwarding errors found for the configured destination. RequestId: ${global.requestId}`,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const allRows = [];
|
|
72
|
+
let shouldDownload = true;
|
|
73
|
+
|
|
74
|
+
// If filename is provided, check if it has a .csv extension and if the file exists
|
|
75
|
+
if (filename) {
|
|
76
|
+
if (path.extname(filename).toLowerCase() !== '.csv') {
|
|
77
|
+
this.error('Invalid file type. Provide a filename with a .csv extension.');
|
|
78
|
+
}
|
|
79
|
+
const outputFile = path.resolve(process.cwd(), filename);
|
|
80
|
+
if (fs.existsSync(outputFile)) {
|
|
81
|
+
// If the file exists, check if it is empty
|
|
82
|
+
const stats = fs.statSync(outputFile);
|
|
83
|
+
if (stats.size > 0) {
|
|
84
|
+
this.error(`Make sure the file: ${filename} is empty`);
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
// If the file does not exist, create an empty file
|
|
88
|
+
fs.writeFileSync(outputFile, '');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (totalSize > 0) {
|
|
92
|
+
// Download and process each presigned URL
|
|
93
|
+
for (const { url } of presignedUrls) {
|
|
94
|
+
try {
|
|
95
|
+
logger.info(`[GetLogForwardingErrorsCommand] Downloading from URL: ${url}`);
|
|
96
|
+
const stream = await this.downloadFileContent(url);
|
|
97
|
+
const content = await this.streamToString(stream);
|
|
98
|
+
// Split content into lines, filter out empty lines
|
|
99
|
+
const lines = content.split(/\r?\n/).filter(line => line.trim() !== '');
|
|
100
|
+
allRows.push(...lines);
|
|
101
|
+
} catch (err) {
|
|
102
|
+
this.log(
|
|
103
|
+
`Failed to download or process log file: ${err.message}. RequestId: ${global.requestId}`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// if filename is provided, write the content to the file
|
|
108
|
+
if (filename) {
|
|
109
|
+
const totalSizeKB = (totalSize / 1024).toFixed(2);
|
|
110
|
+
// Get user confirmation before downloading
|
|
111
|
+
shouldDownload = await promptConfirm(
|
|
112
|
+
`The expected file size is ${totalSizeKB} KB. Confirm ${filename} download? (y/n)`,
|
|
113
|
+
);
|
|
114
|
+
if (shouldDownload) {
|
|
115
|
+
const outputFile = path.resolve(process.cwd(), filename);
|
|
116
|
+
const csvContent = allRows.join('\n');
|
|
117
|
+
fs.writeFileSync(outputFile, csvContent + '\n', 'utf8');
|
|
118
|
+
this.log(`Successfully downloaded the log forwarding error logs to ${filename}`);
|
|
119
|
+
} else {
|
|
120
|
+
this.log('Log forwarding errors file not downloaded.');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// If filename is not provided, print the logs to the console
|
|
125
|
+
else {
|
|
126
|
+
this.log(`\nSuccessfully fetched log forwarding errors.`);
|
|
127
|
+
// print the error logs each in a new line starting with >
|
|
128
|
+
allRows.forEach(rows => {
|
|
129
|
+
this.log(`> ${rows}`);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
this.error(
|
|
134
|
+
`No log forwarding error logs available for the configured destination. RequestId: ${global.requestId}`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Download file content from the presigned URL
|
|
140
|
+
async downloadFileContent(url) {
|
|
141
|
+
logger.debug(`[downloadFileContent] Downloading from URL: ${url}`);
|
|
142
|
+
return axios({
|
|
143
|
+
method: 'get',
|
|
144
|
+
url: url,
|
|
145
|
+
responseType: 'stream',
|
|
146
|
+
})
|
|
147
|
+
.then(response => response.data)
|
|
148
|
+
.catch(error => {
|
|
149
|
+
logger.error('Error downloading log forwarding error content:', error.message);
|
|
150
|
+
throw error;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Parse CSV rows from the content
|
|
155
|
+
async streamToString(stream) {
|
|
156
|
+
const chunks = [];
|
|
157
|
+
for await (const chunk of stream) {
|
|
158
|
+
chunks.push(chunk);
|
|
159
|
+
}
|
|
160
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
GetLogForwardingErrorsCommand.description = 'Get log forwarding errors for the mesh.';
|
|
165
|
+
|
|
166
|
+
module.exports = GetLogForwardingErrorsCommand;
|
|
@@ -10,10 +10,10 @@ governing permissions and limitations under the License.
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
const { Command } = require('@oclif/core');
|
|
13
|
-
const { initSdk, initRequestId } = require('
|
|
14
|
-
const logger = require('
|
|
15
|
-
const { ignoreCacheFlag, jsonFlag } = require('
|
|
16
|
-
const { getLogForwarding, getMeshId } = require('
|
|
13
|
+
const { initSdk, initRequestId } = require('../../../../../helpers');
|
|
14
|
+
const logger = require('../../../../../classes/logger');
|
|
15
|
+
const { ignoreCacheFlag, jsonFlag } = require('../../../../../utils');
|
|
16
|
+
const { getLogForwarding, getMeshId } = require('../../../../../lib/smsClient');
|
|
17
17
|
|
|
18
18
|
class GetLogForwardingCommand extends Command {
|
|
19
19
|
static flags = {
|
|
@@ -23,6 +23,8 @@ class GetLogForwardingCommand extends Command {
|
|
|
23
23
|
|
|
24
24
|
static enableJsonFlag = true;
|
|
25
25
|
|
|
26
|
+
static usage = 'api-mesh:config:get:log-forwarding';
|
|
27
|
+
|
|
26
28
|
async run() {
|
|
27
29
|
await initRequestId();
|
|
28
30
|
|
|
@@ -73,6 +75,11 @@ class GetLogForwardingCommand extends Command {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
GetLogForwardingCommand.description = `Get log forwarding details for a
|
|
78
|
+
GetLogForwardingCommand.description = `Get log forwarding details and error logs for a specified mesh.
|
|
79
|
+
|
|
80
|
+
-The 'log-forwarding' command includes the following options:
|
|
81
|
+
|
|
82
|
+
- api-mesh:config:get:log-forwarding : Retrieve log forwarding details for a given mesh.
|
|
83
|
+
- api-mesh:config:get:log-forwarding:errors : Download log forwarding error logs for a selected time period.`;
|
|
77
84
|
|
|
78
85
|
module.exports = GetLogForwardingCommand;
|
|
@@ -13,15 +13,17 @@ governing permissions and limitations under the License.
|
|
|
13
13
|
const { Help, Command } = require('@oclif/core');
|
|
14
14
|
|
|
15
15
|
class ConfigCommand extends Command {
|
|
16
|
+
static summary = 'Manage the configuration for API Mesh';
|
|
17
|
+
|
|
18
|
+
static usage = 'api-mesh:config [COMMAND]';
|
|
19
|
+
|
|
16
20
|
async run() {
|
|
17
21
|
const help = new Help(this.config);
|
|
18
22
|
await help.showHelp(['api-mesh:config', '--help']);
|
|
19
23
|
}
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
ConfigCommand.description = `
|
|
23
|
-
|
|
24
|
-
The 'config' command includes the following options:
|
|
26
|
+
ConfigCommand.description = `The 'config' command includes the following options:
|
|
25
27
|
- set: Set log forwarding details for a given mesh.
|
|
26
28
|
- get: Retrieve log forwarding details for a given mesh.
|
|
27
29
|
- delete: Delete log forwarding details for a given mesh.`;
|
|
@@ -156,7 +156,10 @@ class InitCommand extends Command {
|
|
|
156
156
|
const gitIgnoreFilePath = `${absolutePath}/.gitignore`;
|
|
157
157
|
|
|
158
158
|
await this.cloneFile(gitIgnoreTemplatePath, gitIgnoreFilePath);
|
|
159
|
-
await this.cloneFile(
|
|
159
|
+
await this.cloneFile(
|
|
160
|
+
deployWorkflowPath,
|
|
161
|
+
`${absolutePath}/.github/workflows/deployMesh.yaml`,
|
|
162
|
+
);
|
|
160
163
|
await this.cloneFile(
|
|
161
164
|
loadTestWorkflowPath,
|
|
162
165
|
`${absolutePath}/.github/workflows/loadTest.yaml`,
|
package/src/lib/smsClient.js
CHANGED
|
@@ -1497,6 +1497,47 @@ const deleteLogForwarding = async (organizationCode, projectId, workspaceId, mes
|
|
|
1497
1497
|
}
|
|
1498
1498
|
};
|
|
1499
1499
|
|
|
1500
|
+
/**
|
|
1501
|
+
* Get log forwarding errors for a given mesh within a specified time range.
|
|
1502
|
+
* @param {string} organizationCode - The IMS org code
|
|
1503
|
+
* @param {string} projectId - The project ID
|
|
1504
|
+
* @param {string} workspaceId - The workspace ID
|
|
1505
|
+
* @param {string} meshId - The mesh ID
|
|
1506
|
+
*/
|
|
1507
|
+
const getLogForwardingErrors = async (organizationCode, projectId, workspaceId, meshId) => {
|
|
1508
|
+
const { accessToken } = await getDevConsoleConfig();
|
|
1509
|
+
const config = {
|
|
1510
|
+
method: 'GET',
|
|
1511
|
+
url: `${SMS_BASE_URL}/organizations/${organizationCode}/projects/${projectId}/workspaces/${workspaceId}/meshes/${meshId}/log/forwarding/errors`,
|
|
1512
|
+
headers: {
|
|
1513
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
1514
|
+
'x-request-id': global.requestId,
|
|
1515
|
+
'x-api-key': SMS_API_KEY,
|
|
1516
|
+
},
|
|
1517
|
+
};
|
|
1518
|
+
logger.info('Initiating GET %s', config.url);
|
|
1519
|
+
try {
|
|
1520
|
+
const response = await axios(config);
|
|
1521
|
+
|
|
1522
|
+
logger.info('Response from GET %s', response.status);
|
|
1523
|
+
|
|
1524
|
+
if (response?.status === 200) {
|
|
1525
|
+
logger.info(`Log forwarding error Presigned urls: ${objToString(response, ['data'])}`);
|
|
1526
|
+
const { presignedUrls, totalSize } = response.data;
|
|
1527
|
+
return {
|
|
1528
|
+
presignedUrls,
|
|
1529
|
+
totalSize,
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
} catch (error) {
|
|
1533
|
+
logger.error(`Error fetching log forwarding errors presigned urls: ${error}`);
|
|
1534
|
+
return {
|
|
1535
|
+
urls: {},
|
|
1536
|
+
totalSize: 0,
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
|
|
1500
1541
|
module.exports = {
|
|
1501
1542
|
getApiKeyCredential,
|
|
1502
1543
|
describeMesh,
|
|
@@ -1521,4 +1562,5 @@ module.exports = {
|
|
|
1521
1562
|
setLogForwarding,
|
|
1522
1563
|
getLogForwarding,
|
|
1523
1564
|
deleteLogForwarding,
|
|
1565
|
+
getLogForwardingErrors,
|
|
1524
1566
|
};
|
|
@@ -25,6 +25,20 @@ jobs:
|
|
|
25
25
|
uses: actions/setup-node@v4
|
|
26
26
|
with:
|
|
27
27
|
node-version: ${{ matrix.node-version }}
|
|
28
|
+
- name: Validate Secrets
|
|
29
|
+
run: |
|
|
30
|
+
if
|
|
31
|
+
[ -z "${{ secrets.CLIENTID }}" ] ||
|
|
32
|
+
[ -z "${{ secrets.CLIENTSECRET }}" ] ||
|
|
33
|
+
[ -z "${{ secrets.TECHNICALACCID }}" ] ||
|
|
34
|
+
[ -z "${{ secrets.TECHNICALACCEMAIL }}" ] ||
|
|
35
|
+
[ -z "${{ secrets.IMSORGID }}" ] ||
|
|
36
|
+
[ -z "${{ secrets.ORGID }}" ] ||
|
|
37
|
+
[ -z "${{ secrets.PROJECTID }}" ] ||
|
|
38
|
+
[ -z "${{ secrets.WORKSPACEID }}" ]; then
|
|
39
|
+
echo "Please set all required secrets: CLIENTID, CLIENTSECRET, TECHNICALACCID, TECHNICALACCEMAIL, IMSORGID, ORGID, PROJECTID, WORKSPACEID"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
28
42
|
- name: Setup CLI
|
|
29
43
|
uses: adobe/aio-cli-setup-action@1.3.0
|
|
30
44
|
with:
|
|
@@ -51,13 +65,29 @@ jobs:
|
|
|
51
65
|
run: aio console:project:select ${{ secrets.PROJECTID }}
|
|
52
66
|
- name: Select workspace
|
|
53
67
|
run: aio console:workspace:select ${{ secrets.WORKSPACEID }}
|
|
54
|
-
- name:
|
|
68
|
+
- name: Print AIO CLI Config
|
|
69
|
+
run: aio config list
|
|
70
|
+
- name: Get Mesh
|
|
71
|
+
id: get_mesh
|
|
72
|
+
continue-on-error: true
|
|
55
73
|
run: |
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
echo
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
74
|
+
output=$(aio api-mesh:get 2>&1)
|
|
75
|
+
# Escape the output and replace newlines with %0A
|
|
76
|
+
escaped_output=$(echo "$output" | tr -d '\r' | tr '\n' ' ')
|
|
77
|
+
echo "mesh_output=$escaped_output" >> $GITHUB_OUTPUT
|
|
78
|
+
echo "$output"
|
|
79
|
+
- name: Debug Get Mesh Output
|
|
80
|
+
continue-on-error: true
|
|
81
|
+
run: echo "Get Mesh Output - ${{ steps.get_mesh.outputs.mesh_output }}"
|
|
82
|
+
- name: Create Mesh
|
|
83
|
+
if: ${{ contains(steps.get_mesh.outputs.mesh_output, 'No mesh found') }}
|
|
84
|
+
run: aio api-mesh:create -c mesh.json --env .env
|
|
85
|
+
- name: Update Mesh
|
|
86
|
+
if: ${{ !contains(steps.get_mesh.outputs.mesh_output, 'No mesh found') }}
|
|
63
87
|
run: aio api-mesh:update -c mesh.json --env .env
|
|
88
|
+
- name: Wait for 30 seconds
|
|
89
|
+
run: sleep 30
|
|
90
|
+
- name: Describe Mesh
|
|
91
|
+
run: aio api-mesh:describe
|
|
92
|
+
- name: Get Mesh Status
|
|
93
|
+
run: aio api-mesh:status
|
package/src/templates/readme.md
CHANGED
|
@@ -6,6 +6,13 @@ Use this repo to bootstrap Adobe API Mesh development with ease. Use this repo t
|
|
|
6
6
|
|
|
7
7
|
This repo comes with all the files and dependencies necessary to get started with API Mesh.
|
|
8
8
|
|
|
9
|
+
1. `mesh.json` - sample mesh config with a single source
|
|
10
|
+
2. `.env` - environment file with variables for the config presented in mesh.json
|
|
11
|
+
3. `package.json` - dependencies and scripts to test and deploy meshes
|
|
12
|
+
4. `.vscode/launch.json` - VS Code configuration to setup debugging out of the box. This applies to VS Code on local machines or Codespaces on Github.com
|
|
13
|
+
5. `.devcontainer/devcontainer.json` - Codespaces configuration to setup dev container out of the box. This config will help setup the packages and build the mesh config automatically. As a bonus it also sets up port-forwarding so you can use your favourite GraphQL interface to practice the mesh
|
|
14
|
+
6. `.github/workflows/deployMesh.yaml` - Github workflow to automatically publish mesh config when something is committed to `main`
|
|
15
|
+
|
|
9
16
|
# Local Dev
|
|
10
17
|
|
|
11
18
|
`yarn start mesh.json` - to start the local dev server in watch mode
|
|
@@ -18,6 +25,22 @@ This repo comes with all the files and dependencies necessary to get started wit
|
|
|
18
25
|
|
|
19
26
|
`yarn test:perf` - to start the Performance Testing process locally for development. Make sure to update the `MESH_ENDPOINT` in the `test:perf` command located in the `package.json`
|
|
20
27
|
|
|
28
|
+
# Setup Github Workflows
|
|
29
|
+
|
|
30
|
+
This repo comes with CICD out of the box but it will need Github Secrets to deploy meshes.
|
|
31
|
+
|
|
32
|
+
Please add the following secrets to the repo upon setup. Follow the [CICD guide](https://developer.adobe.com/graphql-mesh-gateway/gateway/cicd/) to learn more about acquiring the required secrets.
|
|
33
|
+
|
|
34
|
+
1. API_KEY
|
|
35
|
+
2. CLIENTID
|
|
36
|
+
3. CLIENTSECRET
|
|
37
|
+
4. IMSORGID
|
|
38
|
+
5. ORGID
|
|
39
|
+
6. PROJECTID
|
|
40
|
+
7. TECHNICALACCEMAIL
|
|
41
|
+
8. TECHNICALACCID
|
|
42
|
+
9. WORKSPACEID
|
|
43
|
+
|
|
21
44
|
# Documentation
|
|
22
45
|
|
|
23
46
|
Check out the [documentation](https://developer.adobe.com/graphql-mesh-gateway/mesh/basic/create-mesh/) for further details on how to create and maintain meshes.
|