Skip to content

Commit 41b61b5

Browse files
committed
Add hostname to tag assignment demo script, showcasing server fetching, tag creation based on hostnames, and detailed reporting of assignment results. Enhance Tidal API client with retry logic for API calls to handle rate limits effectively.
1 parent 930516a commit 41b61b5

File tree

3 files changed

+331
-61
lines changed

3 files changed

+331
-61
lines changed

examples/hostname-to-tag-demo.ts

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import { TidalApiClient } from '../src/api/client';
2+
import { ServerBulkOperations } from '../src/operations/servers';
3+
import { logger } from '../src/utils/logger';
4+
import { loadConfig, getAuthCredentials } from '../src/config/environment';
5+
6+
7+
8+
/**
9+
* Hostname to Tag Assignment Demo
10+
*
11+
* This example demonstrates:
12+
* 1. Fetching all servers from the API
13+
* 2. Creating tags based on hostname values for servers with hostnames
14+
* 3. Applying the created tags to their respective servers
15+
* 4. Generating a report of successful tag assignments
16+
*/
17+
async function hostnameToTagDemo() {
18+
try {
19+
logger.info('=== Hostname to Tag Assignment Demo ===');
20+
21+
// Load configuration and credentials
22+
const config = loadConfig();
23+
const credentials = getAuthCredentials();
24+
25+
// Initialize the client
26+
const client = new TidalApiClient({ workspace: config.workspace });
27+
28+
logger.info('Authenticating with Tidal API...');
29+
await client.authenticate(credentials.username, credentials.password);
30+
logger.info('Authentication successful');
31+
32+
// Initialize server operations
33+
const serverOps = new ServerBulkOperations(client);
34+
35+
// 2. Fetch all servers from the API
36+
logger.info('\n--- Fetching Servers from API ---');
37+
logger.info('Retrieving all servers for hostname to tag assignment...');
38+
39+
const servers = await serverOps.getServers();
40+
logger.info(`Retrieved ${servers.length} servers from the API`);
41+
42+
// 3. Find servers for tag assignment
43+
logger.info('\n--- Identifying Servers for Tag Assignment ---');
44+
45+
const serversForTagAssignment = servers.filter(server =>
46+
server.host_name &&
47+
server.host_name.trim() !== ''
48+
);
49+
50+
logger.info(`Found ${serversForTagAssignment.length} servers with hostname values`);
51+
logger.info(`These will have tags created and applied based on their hostname`);
52+
53+
if (serversForTagAssignment.length > 0) {
54+
logger.info(`Processing tag creation and assignment for ${serversForTagAssignment.length} servers`);
55+
56+
const assignmentResults = {
57+
successful: 0,
58+
failed: 0,
59+
errors: [] as string[],
60+
successfulAssignments: [] as Array<{
61+
serverId: string | number,
62+
hostname: string,
63+
tagId: number,
64+
environment: string | number
65+
}>
66+
};
67+
68+
// Track created/found tags to avoid duplicates
69+
const tagMap = new Map<string, number>();
70+
71+
for (const server of serversForTagAssignment) {
72+
try {
73+
const hostname = server.host_name!;
74+
logger.info(`Processing server ${server.id} with hostname: "${hostname}"`);
75+
76+
let tagId: number;
77+
78+
// Check if tag already exists in our cache
79+
if (tagMap.has(hostname)) {
80+
tagId = tagMap.get(hostname)!;
81+
logger.info(`Using cached tag "${hostname}" with ID: ${tagId}`);
82+
} else {
83+
// Search for existing tag first
84+
logger.info(`Searching for existing tag: "${hostname}"`);
85+
const searchResponse = await client.get(`/tags?search=${encodeURIComponent(hostname)}`);
86+
const existingTags = searchResponse.data as Array<{ id: number, name: string }>;
87+
88+
const existingTag = existingTags.find(tag => tag.name === hostname);
89+
90+
if (existingTag) {
91+
tagId = existingTag.id;
92+
tagMap.set(hostname, tagId);
93+
logger.info(`Found existing tag "${hostname}" with ID: ${tagId}`);
94+
} else {
95+
// Create new tag
96+
logger.info(`Creating new tag: "${hostname}"`);
97+
const createTagResponse = await client.post('/tags', { tag: { name: hostname } });
98+
const createdTag = createTagResponse.data as { id: number, name: string };
99+
100+
if (createdTag && createdTag.id) {
101+
tagId = createdTag.id;
102+
tagMap.set(hostname, tagId);
103+
logger.info(`Created new tag "${hostname}" with ID: ${tagId}`);
104+
} else {
105+
throw new Error('Failed to create tag - no tag returned');
106+
}
107+
}
108+
}
109+
110+
// Get current server to preserve existing tags
111+
logger.info(`Getting current server ${server.id} to preserve existing tags`);
112+
const serverResponse = await client.get(`/servers/${server.id}`);
113+
const currentServer = serverResponse.data as { tag_ids?: number[] };
114+
115+
// Add new tag to existing tags
116+
const existingTagIds = currentServer.tag_ids || [];
117+
const updatedTagIds = [...new Set([...existingTagIds, tagId])]; // Remove duplicates
118+
119+
// Apply tag to server
120+
logger.info(`Applying tag ${tagId} to server ${server.id} (total tags: ${updatedTagIds.length})`);
121+
await client.put(`/servers/${server.id}`, {
122+
server: {
123+
tag_ids: updatedTagIds,
124+
id: server.id
125+
}
126+
});
127+
128+
logger.info(`✅ ${server.id}: tag "${hostname}" (ID: ${tagId}) applied successfully`);
129+
assignmentResults.successful++;
130+
assignmentResults.successfulAssignments.push({
131+
serverId: server.id,
132+
hostname: hostname,
133+
tagId: tagId,
134+
environment: server.environment_id || 'Unknown'
135+
});
136+
137+
} catch (error) {
138+
const errorMessage = `Failed to process ${server.id}: ${error instanceof Error ? error.message : 'Unknown error'}`;
139+
logger.error(errorMessage);
140+
assignmentResults.failed++;
141+
assignmentResults.errors.push(errorMessage);
142+
}
143+
}
144+
145+
logger.info('\n--- Assignment Results ---');
146+
logger.info(`Total servers processed: ${serversForTagAssignment.length}`);
147+
logger.info(`Successful tag assignments: ${assignmentResults.successful}`);
148+
logger.info(`Failed tag assignments: ${assignmentResults.failed}`);
149+
150+
// Report of successful assignments
151+
if (assignmentResults.successfulAssignments.length > 0) {
152+
logger.info('\n--- Successfully Applied Tags ---');
153+
logger.info('┌─────────────┬─────────────────────────────────┬─────────────┬─────────────────┐');
154+
logger.info('│ Server ID │ Hostname → Tag │ Tag ID │ Environment │');
155+
logger.info('├─────────────┼─────────────────────────────────┼─────────────┼─────────────────┤');
156+
157+
assignmentResults.successfulAssignments.forEach(assignment => {
158+
const serverId = assignment.serverId.toString().padEnd(11);
159+
const hostnameTag = assignment.hostname.padEnd(31);
160+
const tagId = assignment.tagId.toString().padEnd(11);
161+
const environment = assignment.environment.toString().padEnd(15);
162+
logger.info(`│ ${serverId}${hostnameTag}${tagId}${environment} │`);
163+
});
164+
165+
logger.info('└─────────────┴─────────────────────────────────┴─────────────┴─────────────────┘');
166+
}
167+
168+
if (assignmentResults.errors.length > 0) {
169+
logger.info('\nErrors encountered:');
170+
assignmentResults.errors.forEach((error, index) => {
171+
logger.error(`${index + 1}. ${error}`);
172+
});
173+
}
174+
} else {
175+
logger.info('No servers found with hostname values to create tags for');
176+
}
177+
178+
// 4. Summary
179+
logger.info('\n--- Summary ---');
180+
logger.info(`Total servers: ${servers.length}`);
181+
logger.info(`Servers processed for tag assignment: ${serversForTagAssignment.length}`);
182+
logger.info(`Servers without hostname: ${servers.length - serversForTagAssignment.length}`);
183+
184+
logger.info('\n=== Hostname to Tag Assignment Completed Successfully ===');
185+
186+
} catch (error) {
187+
logger.error('Demo failed:', error);
188+
throw error;
189+
}
190+
}
191+
192+
// Run the demo if this file is executed directly
193+
if (require.main === module) {
194+
hostnameToTagDemo()
195+
.then(() => {
196+
logger.info('Demo completed successfully');
197+
process.exit(0);
198+
})
199+
.catch((error) => {
200+
logger.error('Demo failed:', error);
201+
process.exit(1);
202+
});
203+
}
204+
205+
export { hostnameToTagDemo };

0 commit comments

Comments
 (0)