Skip to content

Commit

Permalink
chore(ng): start refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
davlgd committed Nov 24, 2024
1 parent 038ddde commit e078da1
Show file tree
Hide file tree
Showing 7 changed files with 743 additions and 490 deletions.
151 changes: 79 additions & 72 deletions bin/clever.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import colors from 'colors/safe.js';
import _sortBy from 'lodash/sortBy.js';

import { getPackageJson } from '../src/load-package-json.cjs';
import * as Formatter from '../src/models/format-string.js';
import * as git from '../src/models/git.js';
import * as Parsers from '../src/parsers.js';
import { handleCommandPromise } from '../src/command-promise-handler.js';
Expand Down Expand Up @@ -46,6 +45,8 @@ import * as logout from '../src/commands/logout.js';
import * as logs from '../src/commands/logs.js';
import * as makeDefault from '../src/commands/makeDefault.js';
import * as ng from '../src/commands/ng.js';
import * as ngMembers from '../src/commands/ng-members.js';
import * as ngPeers from '../src/commands/ng-peers.js';
import * as notifyEmail from '../src/commands/notify-email.js';
import * as open from '../src/commands/open.js';
import * as consoleModule from '../src/commands/console.js';
Expand Down Expand Up @@ -102,34 +103,33 @@ async function run () {
ngIdOrLabel: cliparse.argument('ng', {
description: 'Network Group ID or label',
parser: Parsers.ngIdOrLabel,
// complete: NetworkGroup('xxx'),
}),
ngDescription: cliparse.argument('description', {
description: 'Network Group description',
}),
ngMemberId: cliparse.argument('member-id', {
description: `The member ID: an app ID (e.g.: ${Formatter.formatCode('app_xxx')}), add-on ID (e.g.: ${Formatter.formatCode('addon_xxx')}) or external node category ID`,
description: 'The member ID: an app ID (e.g.: \'app_xxx\'), add-on ID (e.g.: \'addon_xxx\') or external node category ID',
// complete: NetworkGroup('xxx'),
}),
ngMembersIds: cliparse.argument('members-ids', {
description: "Comma separated list of Network Group members IDs ('app_xxx', 'addon_xxx', 'external_xxx')",
parser: Parsers.commaSeparated,
}),
ngMemberDomainName: cliparse.argument('domain-name', {
description: `Member name used in the ${Formatter.formatUrl('<memberName>.members.<ngID>.ng.clever-cloud.com', false)} domain name alias`,
description: 'Member name used in the \'<memberName>.members.<ngID>.ng.clever-cloud.com\', false domain name alias',
}),
ngPeerId: cliparse.argument('peer-id', {
description: 'The peer ID',
// complete: NetworkGroup('xxx'),
}),
ngPeerRole: cliparse.argument('role', {
description: `The peer role, (${Formatter.formatString('client')} or ${Formatter.formatString('server')})`,
description: `The peer role, (${'client'} or ${'server'})`,
parser: Parsers.ngPeerRole,
complete: NetworkGroup.listAvailablePeerRoles,
}),
// FIXME: Add "internal" member type
ngMemberType: cliparse.argument('type', {
description: `The member type (${Formatter.formatString('application')}, ${Formatter.formatString('addon')} or ${Formatter.formatString('external')})`,
description: `The member type (${'application'}, ${'addon'} or ${'external'})`,
parser: Parsers.ngMemberType,
complete: NetworkGroup.listAvailableMemberTypes,
}),
Expand Down Expand Up @@ -202,6 +202,12 @@ async function run () {
// OPTIONS
const opts = {
// Network Groups options
ngIdOrLabel: cliparse.option('ng', {
metavar: 'ng_id_or_label',
description: 'Network Group ID or label',
parser: Parsers.ngIdOrLabel,
// complete: NetworkGroup('xxx'),
}),
ngMembersIds: cliparse.option('members-ids', {
metavar: 'members_ids',
description: "Comma separated list of Network Group members IDs ('app_xxx', 'addon_xxx', 'external_xxx')",
Expand All @@ -216,6 +222,9 @@ async function run () {
metavar: 'member_label',
description: 'The member label',
}),
ngPeerGetConfig: cliparse.flag('config', {
description: 'Get the Wireguard configuration of an external node',
}),
wgPublicKey: cliparse.option('public-key', {
required: false,
metavar: 'public_key',
Expand Down Expand Up @@ -812,85 +821,83 @@ async function run () {
args: [args.alias],
}, makeDefault.makeDefault);

// NETWORK GROUP COMMANDS
const networkGroupsCreateCommand = cliparse.command('create', {
description: 'Create a Network Group',
args: [args.ngLabel],
options: [opts.ngMembersIds, opts.ngDescription, opts.optTags, opts.humanJsonOutputFormat],
}, ng.createNg);
const networkGroupsDeleteCommand = cliparse.command('delete', {
description: 'Delete a Network Group',
args: [args.ngIdOrLabel],
options: [opts.humanJsonOutputFormat],
}, ng.deleteNg);
const networkGroupsListCommand = cliparse.command('list', {
description: 'List available Network Groups with their labels',
options: [opts.humanJsonOutputFormat],
}, ng.listNg);
const networkGroupsGetCommand = cliparse.command('get', {
description: 'Get details about a Network Group',
args: [args.ngIdOrLabel],
options: [opts.humanJsonOutputFormat],
}, ng.getNg);

const networkGroupsMemberListCommand = cliparse.command('list', {
description: 'List members of a Network Group',
// Add option opts.optNgSearchAppId ?
args: [args.ngIdOrLabel],
options: [opts.naturalName, opts.humanJsonOutputFormat],
}, ng.listMembers);
const networkGroupsMemberGetCommand = cliparse.command('get', {
description: 'Get a Network Group member\'s details',
args: [args.ngIdOrLabel, args.ngMemberId],
options: [opts.naturalName, opts.humanJsonOutputFormat],
}, ng.getMember);
const networkGroupsMemberAddCommand = cliparse.command('add', {
// NETWORK GROUPS ADD COMMANDS
const ngMembersAddCommand = cliparse.command('member', {
description: 'Add an app or add-on as a Network Group member',
args: [args.ngIdOrLabel, args.ngMemberId],
options: [opts.ngMemberLabel],
}, ng.addMember);
const networkGroupsMemberRemoveCommand = cliparse.command('remove', {
}, ngMembers.addMember);
const ngMembersAddExternalCommand = cliparse.command('external-peer', {
description: 'Add an external node as a Network Group peer',
args: [args.ngIdOrLabel, args.ngPeerLabel, args.ngPeerRole, args.ngPeerParentMemberId],
options: [opts.humanJsonOutputFormat, opts.wgPublicKey],
}, ngPeers.addExternalPeer);

// NETWORK GROUPS REMOVE COMMANDS
const ngMembersRemoveCommand = cliparse.command('member', {
description: 'Remove an app or add-on from a Network Group',
args: [args.ngIdOrLabel, args.ngMemberId],
}, ng.removeMember);
const networkGroupsMembersCategoryCommand = cliparse.command('members', {
description: 'List commands for interacting with Network Group members',
commands: [networkGroupsMemberListCommand, networkGroupsMemberGetCommand, networkGroupsMemberAddCommand, networkGroupsMemberRemoveCommand],
}, ng.listMembers);
args: [args.ngMemberId],
options: [opts.ngIdOrLabel],
}, ngMembers.removeMember);
const ngPeersRemoveCommand = cliparse.command('peer', {
description: 'Remove an external node from a Network Group',
args: [args.ngPeerId],
options: [opts.ngIdOrLabel],
}, ngPeers.removeExternalPeer);

const networkGroupsPeerListCommand = cliparse.command('list', {
// NETWORK GROUPS LIST COMMANDS
const ngMembersListCommand = cliparse.command('members', {
description: 'List members of a Network Group',
args: [args.ngIdOrLabel],
}, ngMembers.listMembers);
const ngPeersListCommand = cliparse.command('peers', {
description: 'List peers of a Network Group',
args: [args.ngIdOrLabel],
options: [opts.humanJsonOutputFormat],
}, ng.listPeers);
const networkGroupsPeerGetCommand = cliparse.command('get', {
}, ngPeers.listPeers);

// NETWORK GROUPS GET COMMANDS
const ngMembersGetCommand = cliparse.command('member', {
description: 'Get a Network Group member\'s details',
args: [args.ngMemberId],
options: [opts.naturalName, opts.ngIdOrLabel],
}, ngMembers.getMember);
const ngPeersGetCommand = cliparse.command('peer', {
description: 'Get a Network Group peer\'s details',
args: [args.ngIdOrLabel, args.ngPeerId],
args: [args.ngPeerId],
options: [opts.ngPeerGetConfig, opts.ngIdOrLabel],
}, ngPeers.getPeer);

// NETWORK GROUP COMMANDS
const ngListCommand = cliparse.command('list', {
description: 'List Network Groups (default), their members or peers',
options: [opts.humanJsonOutputFormat],
}, ng.getPeer);
const networkGroupsPeerAddExternalCommand = cliparse.command('add-external', {
description: 'Add an external node as a Network Group peer',
args: [args.ngIdOrLabel, args.ngPeerLabel, args.ngPeerRole, args.ngPeerParentMemberId],
options: [opts.humanJsonOutputFormat, opts.wgPublicKey],
}, ng.addExternalPeer);
const networkGroupsPeerRemoveExternalCommand = cliparse.command('remove-external', {
description: 'Remove an external node from a Network Group',
args: [args.ngIdOrLabel, args.ngPeerId],
}, ng.removeExternalPeer);
const networkGroupsPeerGetConfigCommand = cliparse.command('get-config', {
description: 'Get the configuration of an external node',
args: [args.ngIdOrLabel, args.ngPeerId],
commands: [ngMembersListCommand, ngPeersListCommand],
}, ng.listNg);
const ngCreateCommand = cliparse.command('add', {
description: 'Add a Network Group (default), a member or an external peer',
args: [args.ngLabel],
privateOptions: [opts.ngMembersIds, opts.ngDescription, opts.optTags],
commands: [ngMembersAddCommand, ngMembersAddExternalCommand],
}, ng.createNg);
const ngDeleteCommand = cliparse.command('remove', {
description: 'Delete a Network Group (default), a member or an external peer',
args: [args.ngIdOrLabel],
commands: [ngMembersRemoveCommand, ngPeersRemoveCommand],
}, ng.deleteNg);
const ngGetCommand = cliparse.command('get', {
description: 'Get details about a Network Group (default), a member or a peer',
args: [args.ngIdOrLabel],
options: [opts.humanJsonOutputFormat],
}, ng.getExternalPeerConfig);
const networkGroupsPeersCategoryCommand = cliparse.command('peers', {
description: 'List commands for interacting with Network Group peers',
commands: [networkGroupsPeerListCommand, networkGroupsPeerGetCommand, networkGroupsPeerAddExternalCommand, networkGroupsPeerRemoveExternalCommand, networkGroupsPeerGetConfigCommand],
}, ng.listPeers);

commands: [ngMembersGetCommand, ngPeersGetCommand],
}, ng.getNg);
const ngJoinCommand = cliparse.command('join', {
description: 'Join a Network Group (default), a member or an external peer',
args: [args.ngIdOrLabel],
}, ng.joinNg);
const networkGroupsCommand = cliparse.command('ng', {
description: 'Manage Network Groups, their members and peers',
options: [opts.orgaIdOrName],
commands: [networkGroupsCreateCommand, networkGroupsDeleteCommand, networkGroupsListCommand, networkGroupsGetCommand, networkGroupsMembersCategoryCommand, networkGroupsPeersCategoryCommand],
commands: [ngListCommand, ngCreateCommand, ngDeleteCommand, ngGetCommand, ngJoinCommand],
}, ng.listNg);

// NOTIFY-EMAIL COMMAND
Expand Down
102 changes: 102 additions & 0 deletions src/commands/ng-members.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Logger } from '../logger.js';
import * as ng from '../models/ng.js';
import * as ngApi from '@clevercloud/client/cjs/api/v4/network-group.js';
import { sendToApi } from '../models/send-to-api.js';

export async function listMembers (params) {
const [networkGroupIdOrLabel] = params.args;
const { org: orgaIdOrName, 'natural-name': naturalName, format } = params.options;

const ownerId = await ng.getOwnerId(orgaIdOrName);
const networkGroupId = await ng.getId(ownerId, networkGroupIdOrLabel);

Logger.info(`Listing members from Network Group '${networkGroupId}'`);
Logger.info(naturalName);

const result = await ngApi.listNetworkGroupMembers({ ownerId, networkGroupId }).then(sendToApi);
Logger.debug(`Received from API: ${JSON.stringify(result, null, 2)}`);

switch (format) {
case 'json': {
Logger.println(JSON.stringify(result, null, 2));
break;
}
case 'human':
default: {
if (result.length === 0) {
Logger.println('No member found. You can add one with \'clever ng members add\'.');
}
else {
const domainNames = result.map((item) => ({ domainName: item.domainName }));
console.table(domainNames);
}
}
}
}

export async function getMember (params) {
const [networkGroupIdOrLabel, memberId] = params.args;
const { org: orgaIdOrName, 'natural-name': naturalName, format } = params.options;

const ownerId = await ng.getOwnerId(orgaIdOrName);
const networkGroupId = await ng.getId(ownerId, networkGroupIdOrLabel);

Logger.info(`Getting details for member ${memberId} in Network Group ${networkGroupId}`);
Logger.info(`Natural name: ${naturalName}`);
const result = await ngApi.getNetworkGroupMember({ ownerId, networkGroupId, memberId: memberId }).then(sendToApi);
Logger.debug(`Received from API: ${JSON.stringify(result, null, 2)}`);

switch (format) {
case 'json': {
Logger.println(JSON.stringify(result, null, 2));
break;
}
case 'human':
default: {
const domainName = [result].map((item) => ({ domainName: item.domainName }));
console.table(domainName);
}
}
}

export async function addMember (params) {
const [networkGroupIdOrLabel, memberId] = params.args;
const { org: orgaIdOrName, label } = params.options;

const ownerId = await ng.getOwnerId(orgaIdOrName);
const networkGroupId = await ng.getId(ownerId, networkGroupIdOrLabel);
const domainName = `${memberId}.m.${networkGroupId}.ng.clever-cloud.com`;

let type = null;
if (memberId.startsWith('app_')) {
type = 'application';
}
else if (memberId.startsWith('addon_')) {
type = 'addon';
}
else if (memberId.startsWith('external_')) {
type = 'external';
}
else {
// throw new Error(`Member ID ${Formatter.formatString(memberId)} is not a valid format. It should start with 'app_', 'addon_' or 'external_'`);
type = 'addon';
}

const body = { id: memberId, label, domainName: domainName, type };
Logger.debug('Sending body: ' + JSON.stringify(body, null, 2));
await ngApi.createNetworkGroupMember({ ownerId, networkGroupId }, body).then(sendToApi);

Logger.println(`Successfully added member ${memberId} to Network Group ${networkGroupId}.`);
}

export async function removeMember (params) {
const [networkGroupIdOrLabel, memberId] = params.args;
const { org: orgaIdOrName } = params.options;

const ownerId = await ng.getOwnerId(orgaIdOrName);
const networkGroupId = await ng.getId(ownerId, networkGroupIdOrLabel);

await ngApi.deleteNetworkGroupMember({ ownerId, networkGroupId, memberId }).then(sendToApi);

Logger.println(`Successfully removed member ${memberId} from Network Group ${networkGroupId}.`);
}
Loading

0 comments on commit e078da1

Please sign in to comment.