Retrieve Google Cloud Pricing Information with Nodejs - node.js

I'm currently trying to retrieve Google cloud pricing information via Nodejs. The goal is to figure out what the current price of a compute engine instance is for a specific machine type.
Probably I have to use the billing catalog api but I am unable to make it work at all.
https://googleapis.dev/nodejs/billing/latest/google.cloud.billing.v1.CloudCatalog.html
I managed to retrieve the service id via the catalog api but that appears to be pretty pointless so far.
> const { CloudCatalogClient } = require('#google-cloud/billing')
> const client = new CloudCatalogClient()
> const list = await client.listServices()
>
> list.map(s => {
> s.map(a => {
> if(a.displayName === 'Compute Engine'){
> console.log(a)
> }
> })
>
> })
Outcome:
> {
> name: 'services/6F81-5844-456A',
> serviceId: '6F81-5844-456A',
> displayName: 'Compute Engine',
> businessEntityName: 'businessEntities/GCP'
> }
Could somebody help me out a bit? Thank you very much.

I believe you are looking for this
https://cloud.google.com/billing/v1/how-tos/catalog-api
Steps
Get services:
GET https://cloudbilling.googleapis.com/v1/services?key=API_KEY
Getting the list of SKUs for a service :
GET https://cloudbilling.googleapis.com/v1/services/SERVICE_ID/skus?key=API_KEY
See below test cases for the SDK you can probably use exiting SDK
Catalog API test cases

Related

XERO-NODE SDK => How to choose a specific email template

I am using the Xero-node SDK to automatically create client invoices which works well.
At the end of the process, I would like to automatically email the client the invoice.
In the documentation it has the following example:
const xeroTenantId = 'YOUR_XERO_TENANT_ID';
const invoiceID = '00000000-0000-0000-0000-000000000000';
const requestEmpty: RequestEmpty = { };
try {
const response = await xero.accountingApi.emailInvoice(xeroTenantId, invoiceID, requestEmpty);
console.log(response.body || response.response.statusCode)
} catch (err) {
const error = JSON.stringify(err.response.body, null, 2)
console.log(`Status Code: ${err.response.statusCode} => ${error}`);
}
I have 2 questions:
The requestEmpty method does not work in javascript. Does anyone know the correct structure of requestEmpty?
I have used requestEmpty = { } but this throws an error => even though the system does actually send an email (probably a bug)
AND....
Is there a way for me to specify the email template that I would like the invoice to use (if I have specific templates setup in the web version)? Currently it seems to use the default Xero email template.
If you don't get an answer to your first query here, please can you raise it on the SDK page in Github and the Xero SDK team will look into this for you.
With regards to point 2, it is not possible to choose the email template when sending through the API, a basic template is used.

Using the Twilio API, how can I check if a number is in use by a service?

I am trying to create a new messaging service using the Node.js twilio sdk. To do so, I have devised the following workflow.
I've created a new service like so.
client.messaging.v1.services.create({
friendlyName: 'test service,
inboundRequestUrl: 'https://someUrl.com',
inboundMethod: 'POST',
usecase: 'discussion'
})
I list all the numbers I own like so:
client.incomingPhoneNumbers.list()
I assign a number to my service like so (where the serviceSid is the sid of the service created in step 1 and the phoneNumberSid is the sid of one of phone numbers returned in step 2):
client.messaging.v1.services(<serviceSid>)
.phoneNumbers
.create({ phoneNumberSid: <phoneNumberSid> })
I am happy with this workflow, with the exception of one problem. You cannot assign the same number to two different messaging services, so I need to make sure the phone number whose sid I pass into step 3, doesn't already have a service. The problem is that the response I get back from step 2 doesn't tell me whether the numbers are used by another service.
All of this to say, can anyone suggest some way to modify this workflow to be more robust? Ideally, is there some way I can tell from step 2 whether or not a number is already being used by a service, so I know not to pass it in to step 3?
Thanks
Yes, there is a way to do this. To be honest, it's not very nice, but you can iterate over all messages services and test if your phone number (SID) belongs to a mapping of one of the services and then remove this mapping. Once removed, you can assign the phone number to any other messaging service.
async function unbindPhoneFromMessagingServices(phoneNumberSid) {
const allServices = await client.messaging.v1.services.list();
await Promise.all(
allServices.map(async (service) => {
const mapping = client.messaging.v1
.services(service.sid)
.phoneNumbers(phoneNumberSid);
try {
await mapping.fetch();
} catch (e) {
const RESOURCE_NOT_FOUND = e.code === 20404;
if (RESOURCE_NOT_FOUND) {
return;
}
throw e;
}
await mapping.remove();
console.log(
`The phone number was decoupled from messaging service ${service.sid}.`
);
})
);
}
PS: This snippet is taken from one of my repositories. Feel free to check out the complete code on GitHub.

How to query Azure App Insights logs using Node.JS

There is an example how it is possible to query
LogAnalytics Workspace Logs or
Metrics for individual resources
using Node.Js:
But I could not find if there is an option to query Logs from AppInsights or from resource directly.
I need it to automate reporting of the performance, so I am planning to query requests table (we send logs using https://github.com/microsoft/ApplicationInsights-Java). Currently report is done manually using Performance blade of the AppInsights - checking Avg and 99 percentile for requests with specific filters on URL
You can setup logs ingestion from your application to Log Analytics Workspace using Diagnostic Settings. For example, if you host your app in WebApp you can send AppServiceHTTPLogs. And then in your Node.JS app you can use #azure/monitor-query package with a similar query:
let dataset=AppServiceHTTPLogs
| where CsHost == 'PUT_YOUR_HOSTNAME_HERE'
| where ScStatus == 200
| where CsUriStem contains 'FILTER_BY_URL_IF_YOU_NEED_IT';
dataset
| summarize arg_max(TimeTaken, CsUriStem)
| union(dataset
| summarize avg(TimeTaken), percentiles(TimeTaken, 99)
| extend CsUriStem='Overall')
That one is a close approximation of the performance blade from app insights.
And then your whole app could be
const azureLogAnalyticsWorkspaceId = "WORKSPACE_ID";
const logsQueryClient = new LogsQueryClient(new DefaultAzureCredential());
export async function runWebAppPerformance(startDate: Date, endDate: Date) {
const query = "PUT_YOUR_QUERY_HERE";
const result = await logsQueryClient.queryWorkspace(
azureLogAnalyticsWorkspaceId,
query,
{
startTime: startDate, endTime: endDate
}
);
if (result.status === LogsQueryResultStatus.Success) {
const tablesFromResult: LogsTable[] = result.tables;
if (tablesFromResult.length === 0) {
console.log(`No results for query`);
return;
}
processTables(tablesFromResult);
} else {
console.log(`Error processing the query - ${result.partialError}`);
}
}
async function processTables(tablesFromResult: LogsTable[]) {
const table = tablesFromResult[0];
const urlIndex = table.columnDescriptors.findIndex(c => c.name === "CsUriStem");
const timeTakenIndex = table.columnDescriptors.findIndex(c => c.name === "TimeTaken");
const avgIndex = table.columnDescriptors.findIndex(c => c.name === "avg_TimeTaken");
const ninetyNineindex = table.columnDescriptors.findIndex(c => c.name === "percentile_TimeTaken_99");
for (const row of table.rows) {
if (row[urlIndex] === "Overall"){
console.log(`${row[urlIndex]} (ms):`);
console.log(`Average: ${row[avgIndex]}; \t 99%: ${row[ninetyNineindex]}`);
}
else {
console.log(`MAX (ms)`);
console.log(`${row[urlIndex]}: \t ${row[timeTakenIndex]}`);
}
}
}
How to query Azure App Insights logs using Node.JS
In Azure Portal, Create Application Insights Instance and Copy the Instrumentation key from the overview page
Create a sample NodeJS Web App in Visual Studio code
We can add the instrumentation key in localhost or can be updated once after nodejs application is deployed to Azure.Here I have added the required application insight setting and deployed the App
In server.js, add
let appInsights = require('applicationinsights');
appInsights.setup("cc580d32-a7eb-41d7-b0e0-90ea0889fd10");
appInsights.start();
From the root folder of the Application, open the terminal and run
npm install applicationinsights --save
Deploy the Application to Azure
Browse the Application
View Logs in Application Insights
Application Insights queries are based on KQL
Navigate to Azure Portal => Your Application Insights Instance => Logs under Monitoring = > Click on traces
Metrics for individual resources using Node.Js
Navigate to metrics under Monitoring
Please refer Node.js services with Application Insights for more information

Google Analytics RunReport return 7 PERMISSION_DENIED: User does not have sufficient permissions for this property

I want to run a google analytics report using runReport.
I have followed the instructions at https://developers.google.com/analytics/devguides/reporting/data/v1/quickstart-client-libraries and made a copy of the code that uses json-credentials at https://github.com/googleapis/nodejs-analytics-data/blob/main/samples/quickstart_json_credentials.js
I have one Analytics Account with two Properties & Apps - DEV and STAGE.
In each of them I have created a service account with OWNER permissions. After that I created a key and downloaded the generated JSON-file.
I can test and run the API from the "Try this API" link at https://developers.google.com/analytics/devguides/reporting/data/v1/rest/v1beta/properties/runReport for both my properties and it works well for both of them. (But then I use OAuth authentication of course).
However when I run the code using the JSON-credentials the DEV always work. The STAGE always fails. I have tried running the code both from my machine as well as from https://shell.cloud.google.com/ with the same result.
The failure message is:
7 PERMISSION_DENIED: User does not have sufficient permissions for this property. To learn more about Property ID, see https://developers.google.com/analytics/devguides/reporting/data/v1/property-id.
I have checked several times that the DEV and STAGE properties are correct and that the I use the JSON-credentials file associated with the correct property.
In STAGE, where calls always fail I have several times created new service accounts (with Basic->Owner credentials), created keys and downloaded JSON-credentials. But all with the same result. STAGE always fails.
I have compared the permissions for the service accounts in DEV and STAGE and they seems to be identical.
I have read and tried tips from other people with "permission denied" issues here at stack overflow but none that solves my issue.
Are there any authorization logs that I read from google console?
I'm kind of stuck now.
The code I run (properties and file name obfuscated):
"use strict";
function main(propertyId = "YOUR-GA4-PROPERTY-ID", credentialsJsonPath = "") {
propertyId = "27..DEV property";
credentialsJsonPath = "./DEVcredentials.json";
// propertyId = "27..STAGE property";
// credentialsJsonPath = "./STAGEcredentials.json";
const { BetaAnalyticsDataClient } = require("#google-analytics/data");
const analyticsDataClient = new BetaAnalyticsDataClient({
keyFilename: credentialsJsonPath,
});
async function runReport() {
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [
{
startDate: "2020-03-31",
endDate: "today",
},
],
dimensions: [
{
name: "country",
},
],
metrics: [
{
name: "activeUsers",
},
],
});
console.log("Report result:");
response.rows.forEach((row) => {
console.log(row.dimensionValues[0], row.metricValues[0]);
});
}
runReport();
}
process.on("unhandledRejection", (err) => {
console.error(err.message);
process.exitCode = 1;
});
main(...process.argv.slice(2));
User does not have sufficient permissions for this property.
Means that the user who you have authenticated with does not have permissions to access that view. In this case we are talking about properties/${propertyId}
If you are using a service account make sure to grant it permissions at the account level not the view level.
Permissions need to be granted thorough the google analytics website in the admin section

google-cloud/resource' cloud function not listing all projects in response

I am using a cloud function written in node.js to list projects this is the index.js file containing the method, When I trigger this function I am getting only 1 project printed. ProjectA -> the cloud function also resides in ProjectA, I have another ProjectB which is not getting printed which is also in ACTIVE mode. I have owner permission for both the projects.
const {Resource} = require('#google-cloud/resource');
const resource = new Resource();
async function getProjects() {
try {
// Lists all current projects
const [projects] = await resource.getProjects();
console.log(`success in getProjects() call`);
// Set a uniform endTime for all the resulting messages
const endTime = new Date();
const endTimeStr = endTime.toISOString();
// sample 2019-11-12T17:58:26.068483Z
for (var i=0; i<projects.length;i++) {
console.log("Total Projects ",projects.length) //Printing as 1 instead of correct 2
// Only publish messages for active projects
if (projects[i]["metadata"]["lifecycleState"] === config.ACTIVE) {
// Construct a Pub/Sub message
console.log(`About to send Pub/Sub message ${projects[i]}}`);
const pubsubMessage = {
"token": config.METRIC_EXPORT_PUBSUB_VERIFICATION_TOKEN,
"project_id": projects[i]["id"],
"end_time": endTimeStr
}
}
}
} catch(err) {
console.error("Error in getProjects()");
console.error(err);
throw err;
}
}
However if i try the google api link
https://cloud.google.com/resource-manager/reference/rest/v1/projects/list#try-it
I am getting 2 projects as response which i have access to.
When you execute a Cloud Function you choose a service account that will execute it, normally it's the "App Engine default service account (project-id#appspot.gserviceaccount.com), that service account should have the "Project Owner" role.
The API call from the API explorer uses an API key that it's tied to your user account no the service account used to execute the Cloud Functions, that's why it shows you all your projects.
To fix your issue just add the service account, that you're using to execute the Cloud Function, to all your Projects with the Project Owner role, although other roles (like Project Viewer) are enough to list it.

Resources