@fenwave/agent 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/containerManager.js +4 -85
- package/package.json +1 -1
- package/setup/setupWizard.js +12 -87
- package/store/configStore.js +2 -9
package/containerManager.js
CHANGED
|
@@ -70,79 +70,6 @@ class ContainerManager {
|
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
/**
|
|
74
|
-
* Authenticate with AWS ECR
|
|
75
|
-
*/
|
|
76
|
-
async authenticateECR() {
|
|
77
|
-
return new Promise((resolve, reject) => {
|
|
78
|
-
const awsRegion = config.awsRegion;
|
|
79
|
-
const awsAccountId = config.awsAccountId;
|
|
80
|
-
|
|
81
|
-
if (!awsRegion || !awsAccountId) {
|
|
82
|
-
console.log(chalk.yellow('⚠️ AWS ECR configuration not set, skipping ECR authentication'));
|
|
83
|
-
console.log(chalk.gray(' Run "fenwave init" to configure ECR settings'));
|
|
84
|
-
resolve();
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
console.log(chalk.blue('🔐 Authenticating with AWS ECR...'));
|
|
89
|
-
|
|
90
|
-
const authProcess = spawn('aws', [
|
|
91
|
-
'ecr',
|
|
92
|
-
'get-login-password',
|
|
93
|
-
'--region',
|
|
94
|
-
awsRegion,
|
|
95
|
-
]);
|
|
96
|
-
|
|
97
|
-
let authToken = '';
|
|
98
|
-
let errorOutput = '';
|
|
99
|
-
|
|
100
|
-
authProcess.stdout.on('data', (data) => {
|
|
101
|
-
authToken += data.toString();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
authProcess.stderr.on('data', (data) => {
|
|
105
|
-
errorOutput += data.toString();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
authProcess.on('close', (code) => {
|
|
109
|
-
if (code === 0) {
|
|
110
|
-
// Now login to Docker with the auth token
|
|
111
|
-
const loginProcess = spawn('docker', [
|
|
112
|
-
'login',
|
|
113
|
-
'--username',
|
|
114
|
-
'AWS',
|
|
115
|
-
'--password-stdin',
|
|
116
|
-
`${awsAccountId}.dkr.ecr.${awsRegion}.amazonaws.com`,
|
|
117
|
-
]);
|
|
118
|
-
|
|
119
|
-
loginProcess.stdin.write(authToken.trim());
|
|
120
|
-
loginProcess.stdin.end();
|
|
121
|
-
|
|
122
|
-
let loginError = '';
|
|
123
|
-
loginProcess.stderr.on('data', (data) => {
|
|
124
|
-
loginError += data.toString();
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
loginProcess.on('close', (loginCode) => {
|
|
128
|
-
if (loginCode === 0) {
|
|
129
|
-
console.log(chalk.green('✅ Authenticated with ECR'));
|
|
130
|
-
resolve();
|
|
131
|
-
} else {
|
|
132
|
-
console.error(chalk.red('❌ Failed to login to Docker registry:'));
|
|
133
|
-
console.error(loginError);
|
|
134
|
-
reject(new Error('ECR Docker login failed'));
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
} else {
|
|
138
|
-
console.error(chalk.red('❌ Failed to get ECR auth token:'));
|
|
139
|
-
console.error(errorOutput);
|
|
140
|
-
reject(new Error('ECR authentication failed'));
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
73
|
/**
|
|
147
74
|
* Check if image exists locally
|
|
148
75
|
*/
|
|
@@ -158,7 +85,7 @@ class ContainerManager {
|
|
|
158
85
|
}
|
|
159
86
|
|
|
160
87
|
/**
|
|
161
|
-
* Pull the Fenwave DevApp image from
|
|
88
|
+
* Pull the Fenwave DevApp image from GHCR
|
|
162
89
|
*/
|
|
163
90
|
async pullImage() {
|
|
164
91
|
return new Promise(async (resolve, reject) => {
|
|
@@ -169,7 +96,7 @@ class ContainerManager {
|
|
|
169
96
|
console.log(chalk.green('✅ Image already exists locally, checking for updates...'));
|
|
170
97
|
}
|
|
171
98
|
|
|
172
|
-
console.log(chalk.blue('📥 Pulling Fenwave DevApp image
|
|
99
|
+
console.log(chalk.blue('📥 Pulling Fenwave DevApp image...'));
|
|
173
100
|
console.log(chalk.gray(` Image: ${DOCKER_IMAGE}`));
|
|
174
101
|
|
|
175
102
|
const pullProcess = spawn('docker', ['pull', DOCKER_IMAGE], {
|
|
@@ -234,22 +161,14 @@ class ContainerManager {
|
|
|
234
161
|
// Stop existing container if running
|
|
235
162
|
await this.stopContainer();
|
|
236
163
|
|
|
237
|
-
//
|
|
238
|
-
try {
|
|
239
|
-
await this.authenticateECR();
|
|
240
|
-
} catch (ecrError) {
|
|
241
|
-
console.log(chalk.yellow('⚠️ ECR authentication failed, attempting to use cached image...'));
|
|
242
|
-
// Continue with cached image if authentication fails
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Pull image from ECR
|
|
164
|
+
// Pull image from GHCR (public registry, no auth required)
|
|
246
165
|
try {
|
|
247
166
|
await this.pullImage();
|
|
248
167
|
} catch (pullError) {
|
|
249
168
|
console.log(chalk.yellow('⚠️ Image pull failed, checking for local image...'));
|
|
250
169
|
const imageExists = await this.imageExistsLocally();
|
|
251
170
|
if (!imageExists) {
|
|
252
|
-
throw new Error('No local image available and pull failed. Please check your
|
|
171
|
+
throw new Error('No local image available and pull failed. Please check your network connection.');
|
|
253
172
|
}
|
|
254
173
|
console.log(chalk.green('✅ Using cached local image'));
|
|
255
174
|
}
|
package/package.json
CHANGED
package/setup/setupWizard.js
CHANGED
|
@@ -36,10 +36,9 @@ import {
|
|
|
36
36
|
SetupStep,
|
|
37
37
|
isSetupInProgress,
|
|
38
38
|
} from "../store/setupState.js";
|
|
39
|
-
import { authenticateDockerWithECR } from "../utils/ecrAuth.js";
|
|
40
39
|
import { initializeConfig } from "../store/configStore.js";
|
|
41
40
|
|
|
42
|
-
const TOTAL_STEPS = 7
|
|
41
|
+
const TOTAL_STEPS = 6; // Reduced from 7 - no ECR auth step needed for GHCR
|
|
43
42
|
|
|
44
43
|
/**
|
|
45
44
|
* Setup Wizard Orchestrator
|
|
@@ -49,8 +48,6 @@ export class SetupWizard {
|
|
|
49
48
|
constructor(options = {}) {
|
|
50
49
|
this.backendUrl = options.backendUrl || "http://localhost:7007";
|
|
51
50
|
this.frontendUrl = options.frontendUrl || "http://localhost:3000";
|
|
52
|
-
this.awsRegion = options.awsRegion || "eu-west-1";
|
|
53
|
-
this.awsAccountId = options.awsAccountId || null; // Will be set from Backstage during registration
|
|
54
51
|
this.skipPrerequisites = options.skipPrerequisites || false;
|
|
55
52
|
this.registrationToken = options.token || null;
|
|
56
53
|
}
|
|
@@ -67,8 +64,6 @@ export class SetupWizard {
|
|
|
67
64
|
const agentConfig = {
|
|
68
65
|
backendUrl: this.backendUrl,
|
|
69
66
|
frontendUrl: this.frontendUrl,
|
|
70
|
-
awsRegion: this.awsRegion,
|
|
71
|
-
awsAccountId: this.awsAccountId,
|
|
72
67
|
};
|
|
73
68
|
|
|
74
69
|
initializeConfig(agentConfig);
|
|
@@ -76,10 +71,6 @@ export class SetupWizard {
|
|
|
76
71
|
displayInfo("Agent configuration initialized:");
|
|
77
72
|
displayKeyValue("Backend URL", this.backendUrl);
|
|
78
73
|
displayKeyValue("Frontend URL", this.frontendUrl);
|
|
79
|
-
displayKeyValue("AWS Region", this.awsRegion);
|
|
80
|
-
if (this.awsAccountId) {
|
|
81
|
-
displayKeyValue("AWS Account ID", this.awsAccountId);
|
|
82
|
-
}
|
|
83
74
|
console.log("");
|
|
84
75
|
|
|
85
76
|
// Check if already registered
|
|
@@ -116,19 +107,16 @@ export class SetupWizard {
|
|
|
116
107
|
// Step 2: Device Registration
|
|
117
108
|
const registrationData = await this.registrationStep();
|
|
118
109
|
|
|
119
|
-
// Step 3:
|
|
120
|
-
await this.dockerRegistryStep(registrationData);
|
|
121
|
-
|
|
122
|
-
// Step 4: Pull DevApp Image
|
|
110
|
+
// Step 3: Pull DevApp Image (GHCR is public, no auth required)
|
|
123
111
|
await this.pullImageStep(registrationData);
|
|
124
112
|
|
|
125
|
-
// Step
|
|
113
|
+
// Step 4: NPM Configuration
|
|
126
114
|
await this.npmConfigStep(registrationData);
|
|
127
115
|
|
|
128
|
-
// Step
|
|
116
|
+
// Step 5: Start Agent (optional)
|
|
129
117
|
await this.startAgentStep();
|
|
130
118
|
|
|
131
|
-
// Step
|
|
119
|
+
// Step 6: Complete
|
|
132
120
|
this.displayComplete(registrationData);
|
|
133
121
|
|
|
134
122
|
// Clear setup state
|
|
@@ -288,73 +276,10 @@ export class SetupWizard {
|
|
|
288
276
|
}
|
|
289
277
|
|
|
290
278
|
/**
|
|
291
|
-
* Step 3:
|
|
292
|
-
*/
|
|
293
|
-
async dockerRegistryStep(registrationData) {
|
|
294
|
-
displayStep(3, TOTAL_STEPS, "Docker Registry Configuration");
|
|
295
|
-
|
|
296
|
-
const shouldConfigure = await promptConfirmation(
|
|
297
|
-
"Configure AWS ECR for Fenwave images?",
|
|
298
|
-
true
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
if (!shouldConfigure) {
|
|
302
|
-
displayInfo("Skipping Docker registry configuration");
|
|
303
|
-
saveSetupProgress(SetupStep.DOCKER_REGISTRY, { skipped: true });
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const { awsRegion, awsAccountId } = registrationData.registryConfig;
|
|
308
|
-
|
|
309
|
-
displayInfo(`Authenticating with AWS ECR (${awsRegion})...`);
|
|
310
|
-
displayInfo(
|
|
311
|
-
"🔐 Using Backstage-controlled credential flow (temporary credentials)"
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
try {
|
|
315
|
-
// Use Backstage-controlled credential flow
|
|
316
|
-
const authResult = await authenticateDockerWithECR(this.backendUrl);
|
|
317
|
-
|
|
318
|
-
displaySuccess("AWS ECR authenticated successfully");
|
|
319
|
-
displayInfo(`✅ Credentials expire at: ${authResult.expiration}`);
|
|
320
|
-
displayInfo(`📦 Registry: ${authResult.registryUri}`);
|
|
321
|
-
|
|
322
|
-
saveSetupProgress(SetupStep.DOCKER_REGISTRY, {
|
|
323
|
-
awsRegion: authResult.region,
|
|
324
|
-
awsAccountId: authResult.accountId,
|
|
325
|
-
registryUri: authResult.registryUri,
|
|
326
|
-
expiration: authResult.expiration,
|
|
327
|
-
});
|
|
328
|
-
} catch (error) {
|
|
329
|
-
displayError("Failed to authenticate with AWS ECR");
|
|
330
|
-
displayError(`Error: ${error.message}`);
|
|
331
|
-
displayWarning(
|
|
332
|
-
"Make sure your device is registered and Backstage is running"
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
const shouldContinue = await promptConfirmation(
|
|
336
|
-
"Continue without ECR authentication?",
|
|
337
|
-
true
|
|
338
|
-
);
|
|
339
|
-
if (!shouldContinue) {
|
|
340
|
-
throw createError(
|
|
341
|
-
ErrorCode.ECR_AUTH_FAILED,
|
|
342
|
-
"ECR authentication failed"
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
saveSetupProgress(SetupStep.DOCKER_REGISTRY, {
|
|
347
|
-
failed: true,
|
|
348
|
-
error: error.message,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Step 4: Pull Fenwave DevApp Image
|
|
279
|
+
* Step 3: Pull Fenwave DevApp Image (GHCR is public, no auth required)
|
|
355
280
|
*/
|
|
356
281
|
async pullImageStep(registrationData) {
|
|
357
|
-
displayStep(
|
|
282
|
+
displayStep(3, TOTAL_STEPS, "Pull Fenwave DevApp Image");
|
|
358
283
|
|
|
359
284
|
const shouldPull = await promptConfirmation(
|
|
360
285
|
"Pull Fenwave DevApp Docker image?",
|
|
@@ -412,10 +337,10 @@ export class SetupWizard {
|
|
|
412
337
|
}
|
|
413
338
|
|
|
414
339
|
/**
|
|
415
|
-
* Step
|
|
340
|
+
* Step 4: NPM Configuration
|
|
416
341
|
*/
|
|
417
342
|
async npmConfigStep(registrationData) {
|
|
418
|
-
displayStep(
|
|
343
|
+
displayStep(4, TOTAL_STEPS, "NPM Configuration");
|
|
419
344
|
|
|
420
345
|
const { npmToken } = registrationData;
|
|
421
346
|
|
|
@@ -430,10 +355,10 @@ export class SetupWizard {
|
|
|
430
355
|
}
|
|
431
356
|
|
|
432
357
|
/**
|
|
433
|
-
* Step
|
|
358
|
+
* Step 5: Start Agent (optional)
|
|
434
359
|
*/
|
|
435
360
|
async startAgentStep() {
|
|
436
|
-
displayStep(
|
|
361
|
+
displayStep(5, TOTAL_STEPS, "Start Agent Service");
|
|
437
362
|
|
|
438
363
|
const shouldStart = await promptConfirmation("Start the agent now?", true);
|
|
439
364
|
|
|
@@ -453,7 +378,7 @@ export class SetupWizard {
|
|
|
453
378
|
* Display completion message
|
|
454
379
|
*/
|
|
455
380
|
displayComplete(registrationData) {
|
|
456
|
-
displayStep(
|
|
381
|
+
displayStep(6, TOTAL_STEPS, "Setup Complete! 🎉");
|
|
457
382
|
|
|
458
383
|
console.log("");
|
|
459
384
|
displayHeader("Setup Summary");
|
package/store/configStore.js
CHANGED
|
@@ -25,10 +25,8 @@ const DEFAULT_CONFIG = {
|
|
|
25
25
|
registriesDir: 'registries',
|
|
26
26
|
containerDataDir: '/data',
|
|
27
27
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
awsAccountId: null, // Set during registration from Backstage
|
|
31
|
-
dockerImage: null, // Will be computed if awsAccountId is set
|
|
28
|
+
// Docker Image (GHCR - public registry, no auth required)
|
|
29
|
+
dockerImage: 'ghcr.io/fenleap/fenwave/dev-app:latest',
|
|
32
30
|
|
|
33
31
|
// Other Settings
|
|
34
32
|
authTimeoutMs: 60000,
|
|
@@ -68,11 +66,6 @@ export function loadConfig() {
|
|
|
68
66
|
config.appBuilderUrl = config.backendUrl;
|
|
69
67
|
}
|
|
70
68
|
|
|
71
|
-
// Only compute dockerImage if awsAccountId is configured
|
|
72
|
-
if (!config.dockerImage && config.awsAccountId && config.awsRegion) {
|
|
73
|
-
config.dockerImage = `${config.awsAccountId}.dkr.ecr.${config.awsRegion}.amazonaws.com/fenwave/devapp:latest`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
69
|
// Fall back to environment variables if config values are not set
|
|
77
70
|
config.backendUrl = config.backendUrl || process.env.BACKEND_URL || DEFAULT_CONFIG.backendUrl;
|
|
78
71
|
config.frontendUrl = config.frontendUrl || process.env.FRONTEND_URL || DEFAULT_CONFIG.frontendUrl;
|