Skip to content

Instantly share code, notes, and snippets.

@dylanmartin
Last active January 17, 2025 16:37
Show Gist options
  • Save dylanmartin/72fe50b82c9a185b6cbf80775d669d80 to your computer and use it in GitHub Desktop.
Save dylanmartin/72fe50b82c9a185b6cbf80775d669d80 to your computer and use it in GitHub Desktop.
const axios = require('axios');
const gql = require('graphql-tag');
const fs = require('fs')
const path = require('path');
const apiUrl = "https://coinstac.rs.gsu.edu/api"; // Base API URL
// -----------------------------
// Authentication
// -----------------------------
/**
* Authenticate and retrieve a token.
*/
async function getToken(username, password) {
try {
const response = await axios.post(`${apiUrl}/authenticate`, { username, password });
return response.data.id_token;
} catch (error) {
console.error("Authentication failed:", error);
return null;
}
}
// -----------------------------
// GraphQL Helper Functions
// -----------------------------
/**
* Execute a GraphQL mutation.
*/
async function callGraphQLMutation(mutation, variables = {}, token) {
try {
const response = await axios.post(
`${apiUrl}/graphql`,
{ query: mutation, variables },
{ headers: { Authorization: `Bearer ${token}` } }
);
return response.data;
} catch (error) {
console.error("GraphQL mutation error:", error);
return null;
}
}
/**
* Execute a GraphQL query.
*/
async function callGraphQLQuery(query, token) {
try {
const response = await axios.post(
`${apiUrl}/graphql`,
{ query: query },
{ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` } }
);
if (response.data.errors) {
console.error("GraphQL query errors:", response.data.errors);
return null;
}
return response.data.data;
} catch (error) {
console.error("GraphQL query error:", error);
return null;
}
}
// -----------------------------
// Queries and Mutations
// -----------------------------
const generateHeadlessClientApiKeyMutation = `
mutation($headlessClientId: ID!) {
generateHeadlessClientApiKey(headlessClientId: $headlessClientId)
}
`;
const fetchAllHeadlessClientsQuery = `
query {
fetchAllHeadlessClients {
id
name
computationWhitelist
owners
hasApiKey
}
}
`;
const createHeadlessClientMutation = `
mutation($data: HeadlessClientInput!) {
createHeadlessClient(data: $data) {
id
name
hasApiKey
}
}
`;
const deleteHeadlessClientMutation = `
mutation($headlessClientId: ID!) {
deleteHeadlessClient(headlessClientId: $headlessClientId) {
id
name
}
}
`;
const updateHeadlessClientMutation = `
mutation($headlessClientId: ID!, $data: HeadlessClientInput!) {
updateHeadlessClient(headlessClientId: $headlessClientId, data: $data) {
id
name
computationWhitelist
owners
hasApiKey
}
}
`;
// -----------------------------
// Business Logic Functions
// -----------------------------
/**
* Fetch all headless clients.
*/
async function getHeadlessClients(token) {
const response = await callGraphQLQuery(fetchAllHeadlessClientsQuery, token);
return response ? response.fetchAllHeadlessClients : [];
}
/**
* Generate an API key for a headless client.
*/
async function generateApiKey(token, clientId) {
const variables = { headlessClientId: clientId };
const data = await callGraphQLMutation(generateHeadlessClientApiKeyMutation, variables, token);
return data?.data?.generateHeadlessClientApiKey || null;
}
/**
* Create headless client entities for multiple datasets.
*/
async function getComputationWhitelistFromFile(datasetName) {
try {
const fileName = `${datasetName}.json`;
const filePath = path.join(__dirname, 'headlessClientEntityDocs', fileName);
// Check if the file exists
if (!fs.existsSync(filePath)) {
console.warn(`File not found for dataset: ${datasetName}`);
return null;
}
// Read and parse the file
const fileContent = await fs.promises.readFile(filePath, 'utf-8');
const jsonData = JSON.parse(fileContent);
// Return the "computationWhitelist" key if it exists
if (jsonData.computationWhitelist) {
return jsonData.computationWhitelist;
} else {
console.warn(`"computationWhitelist" key not found in file: ${fileName}`);
return null;
}
} catch (error) {
console.error(`Error while retrieving computation whitelist for dataset: ${datasetName}`);
console.error(error.message);
console.error(error.stack);
return null;
}
}
async function createHeadlessClientEntities({ prefix, datasetNames, token }) {
return Promise.all(datasetNames.map(async datasetName => {
const computationWhitelist = await getComputationWhitelistFromFile(datasetName);
const newClientName = `${prefix}-${datasetName}`;
const variables = {
data: {
name: newClientName,
computationWhitelist: computationWhitelist || [],
owners: null, // Adjust ownership structure if needed
},
};
try {
const response = await callGraphQLMutation(createHeadlessClientMutation, variables, token);
if (response?.data?.createHeadlessClient) {
console.log(`Created headless client: ${response.data.createHeadlessClient.name}`);
return response.data.createHeadlessClient;
} else {
console.error(`Failed to create headless client for dataset: ${datasetName}`);
console.error(`GraphQL response errors: ${JSON.stringify(response?.errors, null, 2)}`);
console.error(`Variables: ${JSON.stringify(variables, null, 2)}`);
return null;
}
} catch (error) {
console.error(`Exception occurred while creating headless client for dataset: ${datasetName}`);
console.error(`Error: ${error.message}`);
console.error(`Stack trace: ${error.stack}`);
console.error(`Variables: ${JSON.stringify(variables, null, 2)}`);
return null;
}
}));
}
/**
* Generate configuration for clients matching a prefix.
*/
async function createHeadlessClientConfig({ prefix, token }) {
const allHeadlessClients = await getHeadlessClients(token);
const filteredClients = allHeadlessClients.filter(client => client.name.includes(prefix));
return Promise.all(filteredClients.map(async client => {
const apiKey = await generateApiKey(token, client.id);
return { id: client.id, name: client.name, apiKey };
}));
}
/**
* Delete headless client entities matching a prefix.
*/
async function deleteHeadlessClientEntities({ prefix, token }) {
const allHeadlessClients = await getHeadlessClients(token);
const filteredClients = allHeadlessClients.filter(client => client.name.includes(prefix));
return Promise.all(filteredClients.map(async client => {
const variables = { headlessClientId: client.id };
const response = await callGraphQLMutation(deleteHeadlessClientMutation, variables, token);
if (response?.data?.deleteHeadlessClient) {
console.log(`Deleted headless client: ${response.data.deleteHeadlessClient.name}`);
} else {
console.error(`Failed to delete headless client with ID: ${client.id}`);
}
}));
}
/**
* Delete all headless clients whose names start with a given prefix.
* @param {string} prefix - The prefix to match client names.
* @param {string} token - Authentication token.
*/
async function deleteHeadlessClientsByPrefix(prefix, token) {
try {
// Fetch all headless clients
const allHeadlessClients = await getHeadlessClients(token);
// Filter clients matching the prefix
const clientsToDelete = allHeadlessClients.filter(client => client.name.startsWith(prefix));
if (clientsToDelete.length === 0) {
console.log(`No headless clients found with prefix: ${prefix}`);
return;
}
console.log(`Found ${clientsToDelete.length} clients to delete with prefix: ${prefix}`);
// Delete each matching client
await Promise.all(clientsToDelete.map(async client => {
const variables = { headlessClientId: client.id };
const response = await callGraphQLMutation(deleteHeadlessClientMutation, variables, token);
if (response?.data?.deleteHeadlessClient) {
console.log(`Deleted headless client: ${response.data.deleteHeadlessClient.name}`);
} else {
console.error(`Failed to delete headless client: ${client.name} (ID: ${client.id})`);
if (response?.errors) {
console.error(`GraphQL errors: ${JSON.stringify(response.errors, null, 2)}`);
}
}
}));
console.log(`Completed deletion of clients with prefix: ${prefix}`);
} catch (error) {
console.error(`Error during deletion of clients with prefix: ${prefix}`);
console.error(`Error details: ${error.message}`);
console.error(`Stack trace: ${error.stack}`);
}
}
async function updateHeadlessClient(token, clientId, updateData) {
const variables = {
headlessClientId: clientId,
data: updateData,
};
try {
const response = await callGraphQLMutation(updateHeadlessClientMutation, variables, token);
if (response?.data?.updateHeadlessClient) {
console.log(`Updated headless client: ${response.data.updateHeadlessClient.name}`);
return response.data.updateHeadlessClient;
} else {
console.error(`Failed to update headless client with ID: ${clientId}`);
console.error(`GraphQL response errors: ${JSON.stringify(response?.errors, null, 2)}`);
return null;
}
} catch (error) {
console.error(`Exception occurred while updating headless client with ID: ${clientId}`);
console.error(`Error: ${error.message}`);
console.error(`Stack trace: ${error.stack}`);
return null;
}
}
async function saveAllHeadlessClientConfigurations(token) {
try {
// Fetch all headless clients
const allHeadlessClients = await getHeadlessClients(token);
if (!allHeadlessClients || allHeadlessClients.length === 0) {
console.log("No headless clients found.");
return;
}
// Iterate through each headless client
await Promise.all(
allHeadlessClients.map(async (client) => {
const clientConfig = {
id: client.id,
name: client.name,
computationWhitelist: client.computationWhitelist || [],
owners: client.owners || [],
hasApiKey: client.hasApiKey,
};
// // Generate API key if it doesn't exist
// if (!client.hasApiKey) {
// const apiKey = await generateApiKey(token, client.id);
// if (apiKey) {
// clientConfig.apiKey = apiKey;
// } else {
// console.error(`Failed to generate API key for client: ${client.name}`);
// }
// }
// Save the configuration to a file
const fileName = `${client.name}.json`;
await fs.promises.writeFile(fileName, JSON.stringify(clientConfig, null, 2));
console.log(`Configuration for client "${client.name}" saved to file: ${fileName}`);
})
);
console.log("All client configurations have been saved.");
} catch (error) {
console.error("Error while saving headless client configurations:", error.message);
console.error(error.stack);
}
}
// -----------------------------
// Main Execution
// -----------------------------
(async () => {
const USERNAME = "";
const PASSWORD = "";
const token = await getToken(USERNAME, PASSWORD);
if (!token) {
console.error("Failed to authenticate. Exiting.");
return;
}
const datasetNames = [
"CMI-GICA vault",
"CMI-HealthyBrain-Freesurfer_regression_vault",
"CMI-HealthyBrain-VBM_regression_vault",
"Substance-Use-Freesurfer_regression_vault",
"Substance-Use-VBM_regression_vault",
"SUBSTANCEUSE-GICA vault",
"TReNDS-COBRE-Freesurfer_regression_vault",
"TReNDS-COBRE-GICA vault",
"TReNDS-COBRE-VBM regression vault",
];
const numberOfVaultServers = 1;
for (let i = 0; i < numberOfVaultServers; i++) {
const prefix = `VAULT-TEST-${i+1}`;
console.log(`Creating clients for prefix: ${prefix}`);
await createHeadlessClientEntities({ prefix, datasetNames, token });
console.log(`Generating configuration for prefix: ${prefix}`);
const vaultConfig = await createHeadlessClientConfig({ prefix, token });
const filePath = `vault_config-${prefix}.json`;
await fs.promises.writeFile(filePath, JSON.stringify(vaultConfig, null, 2));
console.log(`Vault Config saved to ${filePath}`);
}
// await deleteHeadlessClientsByPrefix("test-ec2", token);
// await saveAllHeadlessClientConfigurations(token);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment