From 0580e10d887750fd1c46e46476026869ffe464fb Mon Sep 17 00:00:00 2001 From: Richard Vanderpool <49568690+rvanderp3@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:45:12 -0400 Subject: [PATCH] implement remove resource from service account --- TwingateApiClient.mjs | 7 ++ cliCmd/cmd.mjs | 4 + .../cmdRemoveResourceFromServiceAccount.mjs | 73 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 cliCmd/cmdRemoveResourceFromServiceAccount.mjs diff --git a/TwingateApiClient.mjs b/TwingateApiClient.mjs index 75b50d7..f6c1a35 100644 --- a/TwingateApiClient.mjs +++ b/TwingateApiClient.mjs @@ -631,6 +631,13 @@ export class TwingateApiClient { return serviceAccountResponse.serviceAccountUpdate.entity; } + async removeResourceFromServiceAccount(serviceAccountId, resourceId) { + let resourceIds = ( Array.isArray(resourceId) ? resourceId : [resourceId]); + const serviceAccountQuery = "mutation RemoveResourceFromServiceAccount($serviceAccountId:ID!,$resourceIds:[ID]){serviceAccountUpdate(id:$serviceAccountId,removedResourceIds:$resourceIds){error entity{id name resources{edges{node{id name}}}}}}"; + let serviceAccountResponse = await this.exec(serviceAccountQuery, {serviceAccountId, resourceIds} ); + return serviceAccountResponse.serviceAccountUpdate.entity; + } + async addGroupToResource(resourceId, groupIds){ const addGrouptoResourceQuery = "mutation AddGroupToResource($resourceId:ID!,$groupIds:[ID]){resourceUpdate(id:$resourceId,addedGroupIds:$groupIds){error entity{id name groups{edges{node{id name}}}}}}"; let resourceResponse = await this.exec(addGrouptoResourceQuery, {resourceId, groupIds} ); diff --git a/cliCmd/cmd.mjs b/cliCmd/cmd.mjs index 07ac7c7..f8a81a8 100644 --- a/cliCmd/cmd.mjs +++ b/cliCmd/cmd.mjs @@ -11,6 +11,7 @@ import {getListCommand} from "./listCmd.mjs"; import {getRemoveCommands} from "./removeCmd.mjs"; import {getAddUserToGroupCommands, getRemoveUserFromGroupCommands} from "./cmdUserGroup.mjs"; import {getAddResourceToSericeAccountCommands} from "./cmdAddResourceToServiceAccount.mjs"; +import {getRemoveResourceFromServiceAccountCommands} from "./cmdRemoveResourceFromServiceAccount.mjs"; import {getRemoveBulkCommands} from "./removeBulkCmd.mjs"; import {deviceUntrustCommands, deviceTrustCommands} from "./deviceTrustCmd.mjs"; import { @@ -64,6 +65,9 @@ export function getTopLevelCommand(name) { let addResourceToServiceAccount = getAddResourceToSericeAccountCommands(name) if ( addResourceToServiceAccount !== null ) cmd = cmd.command("add_resource", addResourceToServiceAccount) + let removeResourceFromServiceAccount = getRemoveResourceFromServiceAccountCommands(name) + if ( removeResourceFromServiceAccount !== null ) cmd = cmd.command("remove_resource", removeResourceFromServiceAccount) + let generateConnectorTokens = getGenerateConnectorToken(name) if ( generateConnectorTokens !== null ) cmd = cmd.command("generate_token", generateConnectorTokens) diff --git a/cliCmd/cmdRemoveResourceFromServiceAccount.mjs b/cliCmd/cmdRemoveResourceFromServiceAccount.mjs new file mode 100644 index 0000000..dd2d33b --- /dev/null +++ b/cliCmd/cmdRemoveResourceFromServiceAccount.mjs @@ -0,0 +1,73 @@ +import {Command, EnumType} from "https://deno.land/x/cliffy/command/mod.ts"; +import { + loadClientForCLI, + loadNetworkAndApiKey, + tryProcessPortRestrictionString +} from "../utils/smallUtilFuncs.mjs"; +import {TwingateApiClient} from "../TwingateApiClient.mjs"; +import {Log} from "../utils/log.js"; + + +const OutputFormat = new EnumType(["text", "json"]); +OutputFormat.TEXT = "text"; +OutputFormat.JSON = "json"; + +export function getRemoveResourceFromServiceAccountCommands(name) { + let cmd = null; + switch (name) { + case "service": + cmd = new Command() + .arguments(" [resourceNamesOrIds...:string]") + .option("-o, --output-format ", "Output format", {default: "text"}) + .description(`Remove resources from a service`) + .action(async (options, serviceAccountId, ...resourceNamesOrIds) => { + + if (!resourceNamesOrIds){ + throw new Error(`Resource names or IDs are not defined.`) + } + + const {networkName, apiKey, client} = await loadClientForCLI(options); + options.apiKey = apiKey; + options.accountName = networkName; + + let resourceIds = resourceNamesOrIds + for ( let x = 0; x < resourceIds.length; x++ ) { + let resourceId = resourceIds[x] + if (!resourceId.startsWith(TwingateApiClient.IdPrefixes.Resource)) { + resourceId = await client.lookupResourceByName(resourceId); + if (resourceId == null) { + throw new Error(`Could not find resource: '${resourceIds[x]}'`) + } else { + resourceIds[x] = resourceId + } + } + } + + let res = await client.removeResourceFromServiceAccount(serviceAccountId, resourceIds); + + let resourceStr = `` + let result = res.resources.edges.map(function(obj) {return obj.node.id}) + + for (const element of resourceIds) { + if (result.includes(element)===false){ + resourceStr += element + ", " + } + } + resourceStr = resourceStr.substring(0, resourceStr.length - 2); + + switch (options.outputFormat) { + case OutputFormat.JSON: + console.log(JSON.stringify(res)); + break; + default: + let msg = `Removed resources ${resourceStr} from ${name} '${res.name}: ${res.id}'` + Log.success(msg); + break; + } + }); + break; + } + return cmd; +} + +