I'm trying to interact with Azure China Resources with Nodejs.
But could not find out how to authenticate the application with Azure China with nodejs SDK.
Tried #azure/arm-storage
import * as msRestNodeAuth from "#azure/ms-rest-nodeauth";
import { StorageManagementClient, StorageManagementModels, StorageManagementMappers } from "#azure/arm-storage";
const subscriptionId = process.env["AZURE_SUBSCRIPTION_ID"];
msRestNodeAuth.interactiveLogin().then((creds) => {
const client = new StorageManagementClient(creds, subscriptionId);
client.operations.list().then((result) => {
console.log("The result is:");
console.log(result);
});
}).catch((err) => {
console.error(err);
});
To connect to Azure China, you will need to specify the environment. Please see the code below:
const msRestNodeAuth = require("#azure/ms-rest-nodeauth");
const Environment = require("#azure/ms-rest-azure-env").Environment;
const mooncake = Environment.ChinaCloud;
msRestNodeAuth.interactiveLogin({
environment: mooncake
}).then((creds) => {
console.log(creds);
}).catch((err) => {
console.error(err);
});
Related
While not a front-end developer, I'm trying to set up a web app to show up a demo for a product. That app is based on the Sigma.js demo app demo repository.
You'll notice that this app relies on a graph which is hosted locally, which is loaded as:
/src/views/Root.tsx :
useEffect(() => {
fetch(`${process.env.PUBLIC_URL}/dataset.json`)
.then((res) => res.json())
.then((dataset: Dataset) => {...
// do things ....
and I wish to replace this by a call to another service which I also host on Cloud Run.
My first guess was to use the gcloud-auth-library, but I could not make it work - especially since it does not seem to support Webpack > 5 (I might be wrong here), the point here this lib introduces many problems in the app, and I thought I'd be better off trying the other way GCP suggests to handle auth tokens: by calling the Metadata server.
So I replaced the code above with:
Root.tsx :
import { getData } from "../getGraphData";
useEffect(() => {
getData()
.then((res) => res.json())
.then((dataset: Dataset) => {
// do even more things!
getGraphData.js :
import { getToken } from "./tokens";
const graphProviderUrl = '<my graph provider service URL>';
export const getData = async () => {
try {
const token = await getToken();
console.log(
"getGraphData.js :: getData : received token",
token
);
const request = await fetch(
`${graphProviderUrl}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const data = await request.json();
console.log("getGraphData.js :: getData : received graph", data);
return data;
} catch (error) {
console.log("getGraphData.js :: getData : error getting graph data", error);
return error.message;
}
};
tokens.js :
const targetAudience = '<my graph provider service base URL>'; // base URL as audience
const metadataServerAddress = "169.254.169.254"; // use this to shortcut DNS call to metadata.google.internal
export const getToken = async () => {
if (tokenExpired()) {
const token = await getValidTokenFromServer();
sessionStorage.setItem("accessToken", token.accessToken);
sessionStorage.setItem("expirationDate", newExpirationDate());
return token.accessToken;
} else {
console.log("tokens.js 11 | token not expired");
return sessionStorage.getItem("accessToken");
}
};
const newExpirationDate = () => {
var expiration = new Date();
expiration.setHours(expiration.getHours() + 1);
return expiration;
};
const tokenExpired = () => {
const now = Date.now();
const expirationDate = sessionStorage.getItem("expirationDate");
const expDate = new Date(expirationDate);
if (now > expDate.getTime()) {
return true; // token expired
}
return false; // valid token
};
const getValidTokenFromServer = async () => {
// get new token from server
try {
const request = await fetch(`http://${metadataServerAddress}/computeMetadata/v1/instance/service-accounts/default/token?audience=${targetAudience}`, {
headers: {
'Metadata-Flavor': 'Google'
}
});
const token = await request.json();
return token;
} catch (error) {
throw new Error("Issue getting new token", error.message);
}
};
I know that this kind of call will need to be done server-side. What I don't know is how to have it happen on a React + Node app. I've tried my best to integrate good practices but most questions related to this topic (request credentials through a HTTP (not HTTPS!) API call) end with answers that just say "you need to do this server-side", without providing more insight into the implementation.
There is a question with similar formulation and setting here but the single answer, no upvote and comments is a bit underwhelming. If the actual answer to the question is "you cannot ever call the metadata server from a react app and need to set up a third-party service to do so (e.g. firebase)", I'd be keen on having it said explicitly!
Please assume I have only a very superficial understanding of node.js and React!
I have uploaded my API project (Node.js project) to AWS ECS container and my project contains swagger documentation. In swagger I want to indicate the current host Ip address that the API is run on but I cannot find the right code to fetch it. There is a solution for that? since I have managed to implement it on .NetCore API.
How does it looks right now:
Thx in advance.
You can make use of AWS ECS metadata endpoint http://172.17.0.1:51678/v1/metadata from an ECS task to fetch details about the container instance. The details fetched can then be used to get the private/public ip address of the instance. Example:
import http from 'http';
import util from 'util';
import AWS from 'aws-sdk';
export const getIPAddresses = async () => {
try {
let options: any = {
hostname: '172.17.0.1',
port: 51678,
path: '/v1/metadata',
method: 'GET'
}
let containerInstanceDetails: any = await httpGet(options);
containerInstanceDetails = JSON.parse(containerInstanceDetails);
const cluster = containerInstanceDetails["Cluster"];
const containerInstanceArn = containerInstanceDetails["ContainerInstanceArn"];
const containerInstanceUUID = containerInstanceArn.split('/')[2];
let params: any = {
cluster: cluster,
containerInstances: [containerInstanceUUID]
}
if (!AWS.config.region) {
AWS.config.update({
region: <your_aws_region>
});
}
const ecs = new AWS.ECS({ 'region': <your_aws_region> });
const ec2 = new AWS.EC2({ 'region': <your_aws_region> });
const describeContainerInstancesAsync = util.promisify(ecs.describeContainerInstances).bind(ecs);
const describeInstancesAsync = util.promisify(ec2.describeInstances).bind(ec2);
let data = await describeContainerInstancesAsync(params);
const ec2InstanceId = data.containerInstances[0].ec2InstanceId;
params = {
InstanceIds: [
ec2InstanceId
]
}
data = await describeInstancesAsync(params);
return [data.Reservations[0].Instances[0].PrivateIpAddress, data.Reservations[0].Instances[0].PublicIpAddress];
}
catch(err) {
console.log(err);
}
}
async function httpGet(options) {
return new Promise((resolve, reject) => {
http.get(options, response => {
response.setEncoding('utf8');
response.on('data', data => {
resolve(data);
});
}).on('error', error => {
reject(error.message);
});
});
}
I am running the following code:
const { initializeApp } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore');
const {firestore} = require("firebase-admin");
const QuerySnapshot = firestore.QuerySnapshot;
initializeApp()
const db = getFirestore();
const initializeListener = (collectionName) => {
console.log('called function');
const query = db.collection(collectionName);
query.onSnapshot((querySnapshot) => {
querySnapshot.docs().
console.log('snapshot received');
querySnapshot.docChanges().forEach((change) => {
console.log('doc change found');
if (change.type === "added") {
console.log("New " + collectionName, change.doc.data());
}
});
}, (erry) => {
console.log(`Encountered error: ${err}`);
});
}
initializeListener('my_collection');
If running whilst offline I don't see the 'snapshot received' message until I go online. If offline persistence should be available here, how do I access it?
You are using the Firebase Admin SDK (a wrapper around the Google Cloud backend SDK), which does not have any sort of persistence on any platform. Offline persistence is only available for the web and client SDKs provided by Firebase. As you can see from the linked documentation:
Note: Offline persistence is supported only in Android, Apple, and web apps.
const msRestAzure = require('ms-rest-azure');
const { GraphRbacManagementClient } = require('azure-graph');
module.exports = async function (context, req) {
try{
const credentials = await msRestAzure.loginWithServicePrincipalSecret(clientId, clientSecret, tanent);
const client = new GraphRbacManagementClient(credentials, tenantId);
const results = await client.users.list();
context.res = {
body: results
};
} catch (error) {
console.log('error==> ',error); // Getting error: Authentication_MissingOrMalformed
context.res = {
body: error
};
}
}
I want to get all users list using azure graph sdk. But after calling the client.users.list() function I'm getting the error ("Authentication_MissingOrMalformed"). How do I fix this error and get all users list.
How to get all users list from Azure Active Directory using Azure Graph SDK (Nodejs) ?
The main problem is missing { tokenAudience: 'graph' }, please refer to my code:
const msRestAzure = require('ms-rest-azure');
const { GraphRbacManagementClient } = require('azure-graph');
module.exports = async function (context, req) {
try{
msRestAzure.loginWithServicePrincipalSecret("clientId", "clientSecret", "tenantId", { tokenAudience: 'graph' }, function (err, credentials) {
if (err) return console.log(err);
const client = new GraphRbacManagementClient(credentials, "tenantId");
client.users.list((err, results, request, response) => {
if (err) return console.log(err);
console.log(JSON.parse(response.body).value.length);
});
});
} catch (error) {
console.log('error==> ',error);
context.res = {
body: error
};
}
}
After running the code above, if the number of users in your AD is greater than 100, it will output 100 because graph api can response 100 users in a page(default is 100).
==================================Update================================
Please check if you have added the permission to the application registered in Azure AD. If you didn't add the permission, please follow the below steps:
1. Go to the application which registered in your Azure AD (It's the application which you use its clientId).
2. Add the permission.
3. Click "Grant admin consent for xxx".
4. After a few minutes, run your code again.
I am using this gcloud command to stop my sql instance following this
gcloud sql instances patch my-sql-instance --activation-policy NEVER
how can I achieve the same in nodejs code?
is there a google library for the sql api in npm?
using googleapis
see also the api reference
const {google} = require('googleapis');
const {auth} = require('google-auth-library');
const sqladmin = google.sqladmin('v1beta4');
auth.getApplicationDefault((_err, authRes) => {
var req = {
auth: authRes.credential,
project: "my-project-id",
instance: "my-instance",
requestBody: {
"settings": {
"activationPolicy": "NEVER"
}
}
};
sqladmin.instances.patch(req, (err, res) => {
if (err) console.error(err);
if (res) console.info(res);
})
});