@alwaysai/device-agent 2.1.2 → 2.1.3
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/lib/application-control/config.d.ts.map +1 -1
- package/lib/application-control/config.js +7 -7
- package/lib/application-control/config.js.map +1 -1
- package/lib/application-control/environment-variables-and-passthrough-update.d.ts +15 -0
- package/lib/application-control/environment-variables-and-passthrough-update.d.ts.map +1 -0
- package/lib/application-control/environment-variables-and-passthrough-update.js +46 -0
- package/lib/application-control/environment-variables-and-passthrough-update.js.map +1 -0
- package/lib/application-control/environment-variables-and-passthrough-update.test.d.ts +2 -0
- package/lib/application-control/environment-variables-and-passthrough-update.test.d.ts.map +1 -0
- package/lib/application-control/environment-variables-and-passthrough-update.test.js +188 -0
- package/lib/application-control/environment-variables-and-passthrough-update.test.js.map +1 -0
- package/lib/application-control/environment-variables.d.ts +64 -4
- package/lib/application-control/environment-variables.d.ts.map +1 -1
- package/lib/application-control/environment-variables.js +86 -11
- package/lib/application-control/environment-variables.js.map +1 -1
- package/lib/application-control/environment-variables.test.js +156 -10
- package/lib/application-control/environment-variables.test.js.map +1 -1
- package/lib/application-control/index.d.ts +4 -4
- package/lib/application-control/index.d.ts.map +1 -1
- package/lib/application-control/index.js +8 -8
- package/lib/application-control/index.js.map +1 -1
- package/lib/application-control/install.d.ts +1 -1
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +27 -26
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/utils.js +6 -6
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-message-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts +2 -2
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +5 -5
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/environment.d.ts +1 -0
- package/lib/environment.d.ts.map +1 -1
- package/lib/environment.js +2 -1
- package/lib/environment.js.map +1 -1
- package/lib/local-connection/constants.d.ts +1 -0
- package/lib/local-connection/constants.d.ts.map +1 -1
- package/lib/local-connection/constants.js +4 -1
- package/lib/local-connection/constants.js.map +1 -1
- package/lib/subcommands/app/env-vars.js +4 -4
- package/lib/subcommands/app/env-vars.js.map +1 -1
- package/package.json +3 -3
- package/readme.md +1 -1
- package/src/application-control/config.ts +9 -9
- package/src/application-control/environment-variables-and-passthrough-update.test.ts +221 -0
- package/src/application-control/environment-variables-and-passthrough-update.ts +56 -0
- package/src/application-control/environment-variables.test.ts +168 -12
- package/src/application-control/environment-variables.ts +91 -9
- package/src/application-control/index.ts +14 -14
- package/src/application-control/install.ts +37 -35
- package/src/application-control/utils.ts +6 -6
- package/src/cloud-connection/device-agent-message-handler.ts +2 -0
- package/src/cloud-connection/shadow-handler.ts +8 -8
- package/src/environment.ts +2 -1
- package/src/local-connection/constants.ts +7 -2
- package/src/subcommands/app/env-vars.ts +8 -8
|
@@ -2,8 +2,9 @@ import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
|
2
2
|
import { readDockerCompose, writeDockerCompose } from './config';
|
|
3
3
|
import {
|
|
4
4
|
convertStringEnvsToKeyVal,
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
getAllEnvVars,
|
|
6
|
+
setEnvVars,
|
|
7
|
+
updateEnvVarsInternal
|
|
7
8
|
} from './environment-variables';
|
|
8
9
|
import { isAppStarted, restartApp } from './status';
|
|
9
10
|
import { buildApp, requireAppReady } from './utils';
|
|
@@ -33,7 +34,7 @@ describe('Test environment variable get and set', () => {
|
|
|
33
34
|
beforeEach(() => {
|
|
34
35
|
jest.clearAllMocks();
|
|
35
36
|
});
|
|
36
|
-
describe('Test
|
|
37
|
+
describe('Test getAllEnvVars()', () => {
|
|
37
38
|
test('get all envs with one service and no envs', async () => {
|
|
38
39
|
const compose = {
|
|
39
40
|
services: {
|
|
@@ -42,7 +43,7 @@ describe('Test environment variable get and set', () => {
|
|
|
42
43
|
};
|
|
43
44
|
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
44
45
|
|
|
45
|
-
const envVars = await
|
|
46
|
+
const envVars = await getAllEnvVars({ projectId: projectId1 });
|
|
46
47
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
47
48
|
projectId: projectId1
|
|
48
49
|
});
|
|
@@ -61,7 +62,7 @@ describe('Test environment variable get and set', () => {
|
|
|
61
62
|
};
|
|
62
63
|
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
63
64
|
|
|
64
|
-
const envVars = await
|
|
65
|
+
const envVars = await getAllEnvVars({ projectId: projectId1 });
|
|
65
66
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
66
67
|
projectId: projectId1
|
|
67
68
|
});
|
|
@@ -82,7 +83,7 @@ describe('Test environment variable get and set', () => {
|
|
|
82
83
|
};
|
|
83
84
|
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
84
85
|
|
|
85
|
-
const envVars = await
|
|
86
|
+
const envVars = await getAllEnvVars({ projectId: projectId1 });
|
|
86
87
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
87
88
|
projectId: projectId1
|
|
88
89
|
});
|
|
@@ -101,7 +102,7 @@ describe('Test environment variable get and set', () => {
|
|
|
101
102
|
};
|
|
102
103
|
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
103
104
|
|
|
104
|
-
const envVars = await
|
|
105
|
+
const envVars = await getAllEnvVars({ projectId: projectId1 });
|
|
105
106
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
106
107
|
projectId: projectId1
|
|
107
108
|
});
|
|
@@ -110,7 +111,7 @@ describe('Test environment variable get and set', () => {
|
|
|
110
111
|
});
|
|
111
112
|
});
|
|
112
113
|
});
|
|
113
|
-
describe('Test
|
|
114
|
+
describe('Test setEnvVars()', () => {
|
|
114
115
|
test('Set one env', async () => {
|
|
115
116
|
const compose = {
|
|
116
117
|
services: {
|
|
@@ -120,7 +121,7 @@ describe('Test environment variable get and set', () => {
|
|
|
120
121
|
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
121
122
|
|
|
122
123
|
const envVars = { alwaysai: { TEST: '1' } };
|
|
123
|
-
await
|
|
124
|
+
await setEnvVars({ projectId: projectId1, envVars });
|
|
124
125
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
125
126
|
projectId: projectId1
|
|
126
127
|
});
|
|
@@ -145,7 +146,7 @@ describe('Test environment variable get and set', () => {
|
|
|
145
146
|
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
146
147
|
|
|
147
148
|
const envVars = { alwaysai: { TEST1: '2', TEST2: '2' } };
|
|
148
|
-
await
|
|
149
|
+
await setEnvVars({ projectId: projectId1, envVars });
|
|
149
150
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
150
151
|
projectId: projectId1
|
|
151
152
|
});
|
|
@@ -174,7 +175,7 @@ describe('Test environment variable get and set', () => {
|
|
|
174
175
|
alwaysai: { TEST1: '2', TEST2: '4' },
|
|
175
176
|
other: { OTHER_TEST: '1' }
|
|
176
177
|
};
|
|
177
|
-
await
|
|
178
|
+
await setEnvVars({ projectId: projectId1, envVars });
|
|
178
179
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
179
180
|
projectId: projectId1
|
|
180
181
|
});
|
|
@@ -202,7 +203,7 @@ describe('Test environment variable get and set', () => {
|
|
|
202
203
|
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
203
204
|
|
|
204
205
|
const envVars = { alwaysai: { TEST1: '', TEST2: '2' } };
|
|
205
|
-
await
|
|
206
|
+
await setEnvVars({ projectId: projectId1, envVars });
|
|
206
207
|
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
207
208
|
projectId: projectId1
|
|
208
209
|
});
|
|
@@ -229,4 +230,159 @@ describe('Test environment variable get and set', () => {
|
|
|
229
230
|
});
|
|
230
231
|
});
|
|
231
232
|
});
|
|
233
|
+
describe('Test updateEnvVarsInternal()', () => {
|
|
234
|
+
test('add env var to project before docker-compose.yaml is written', async () => {
|
|
235
|
+
jest.mocked(readDockerCompose).mockResolvedValue({});
|
|
236
|
+
const newEnvVars = {
|
|
237
|
+
alwaysai: {
|
|
238
|
+
TEST: '1'
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
await expect(
|
|
243
|
+
updateEnvVarsInternal({
|
|
244
|
+
projectId: projectId1,
|
|
245
|
+
envVars: newEnvVars
|
|
246
|
+
})
|
|
247
|
+
).rejects.toThrow(
|
|
248
|
+
`Docker compose file for ${projectId1} has no services!`
|
|
249
|
+
);
|
|
250
|
+
});
|
|
251
|
+
test('add env var to empty environment variables', async () => {
|
|
252
|
+
const compose = {
|
|
253
|
+
services: {
|
|
254
|
+
alwaysai: {}
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
258
|
+
const newEnvVars = {
|
|
259
|
+
alwaysai: {
|
|
260
|
+
TEST: '1'
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
await updateEnvVarsInternal({
|
|
265
|
+
projectId: projectId1,
|
|
266
|
+
envVars: newEnvVars
|
|
267
|
+
});
|
|
268
|
+
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
269
|
+
projectId: projectId1
|
|
270
|
+
});
|
|
271
|
+
expect(jest.mocked(writeDockerCompose)).toBeCalledWith({
|
|
272
|
+
projectId: projectId1,
|
|
273
|
+
dockerCompose: {
|
|
274
|
+
services: {
|
|
275
|
+
alwaysai: {
|
|
276
|
+
environment: ['TEST=1']
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
test('add env var to existing environment variables', async () => {
|
|
283
|
+
const compose = {
|
|
284
|
+
services: {
|
|
285
|
+
alwaysai: {
|
|
286
|
+
environment: ['TEST2=2']
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
291
|
+
const newEnvVars = {
|
|
292
|
+
alwaysai: {
|
|
293
|
+
TEST: '1'
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
await updateEnvVarsInternal({
|
|
298
|
+
projectId: projectId1,
|
|
299
|
+
envVars: newEnvVars
|
|
300
|
+
});
|
|
301
|
+
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
302
|
+
projectId: projectId1
|
|
303
|
+
});
|
|
304
|
+
expect(jest.mocked(writeDockerCompose)).toBeCalledWith({
|
|
305
|
+
projectId: projectId1,
|
|
306
|
+
dockerCompose: {
|
|
307
|
+
services: {
|
|
308
|
+
alwaysai: {
|
|
309
|
+
environment: ['TEST2=2', 'TEST=1']
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
test('add env var to alwaysai service when multiple exist', async () => {
|
|
316
|
+
const compose = {
|
|
317
|
+
services: {
|
|
318
|
+
test: {
|
|
319
|
+
environment: ['TEST1=1', 'TEST2=2']
|
|
320
|
+
},
|
|
321
|
+
alwaysai: {
|
|
322
|
+
environment: ['TEST2=2']
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
327
|
+
const newEnvVars = {
|
|
328
|
+
alwaysai: {
|
|
329
|
+
TEST: '1'
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
await updateEnvVarsInternal({
|
|
334
|
+
projectId: projectId1,
|
|
335
|
+
envVars: newEnvVars
|
|
336
|
+
});
|
|
337
|
+
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
338
|
+
projectId: projectId1
|
|
339
|
+
});
|
|
340
|
+
expect(jest.mocked(writeDockerCompose)).toBeCalledWith({
|
|
341
|
+
projectId: projectId1,
|
|
342
|
+
dockerCompose: {
|
|
343
|
+
services: {
|
|
344
|
+
test: {
|
|
345
|
+
environment: ['TEST1=1', 'TEST2=2']
|
|
346
|
+
},
|
|
347
|
+
alwaysai: {
|
|
348
|
+
environment: ['TEST2=2', 'TEST=1']
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
test('add env var when it already exists for the service', async () => {
|
|
355
|
+
const compose = {
|
|
356
|
+
services: {
|
|
357
|
+
alwaysai: {
|
|
358
|
+
environment: ['TEST=1']
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
jest.mocked(readDockerCompose).mockResolvedValue(compose);
|
|
363
|
+
const newEnvVars = {
|
|
364
|
+
alwaysai: {
|
|
365
|
+
TEST: '1'
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
await updateEnvVarsInternal({
|
|
370
|
+
projectId: projectId1,
|
|
371
|
+
envVars: newEnvVars
|
|
372
|
+
});
|
|
373
|
+
expect(jest.mocked(readDockerCompose)).toBeCalledWith({
|
|
374
|
+
projectId: projectId1
|
|
375
|
+
});
|
|
376
|
+
expect(jest.mocked(writeDockerCompose)).toBeCalledWith({
|
|
377
|
+
projectId: projectId1,
|
|
378
|
+
dockerCompose: {
|
|
379
|
+
services: {
|
|
380
|
+
alwaysai: {
|
|
381
|
+
environment: ['TEST=1']
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
});
|
|
232
388
|
});
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
+
import { EnvVars } from '@alwaysai/device-agent-schemas';
|
|
1
2
|
import { JsSpawner } from 'alwaysai/lib/util';
|
|
2
|
-
import { readDockerCompose, writeDockerCompose } from './config';
|
|
3
|
-
import { buildApp, getAppDir, requireAppReady } from './utils';
|
|
4
|
-
import { logger } from '../util/logger';
|
|
5
3
|
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
4
|
+
import { logger } from '../util/logger';
|
|
5
|
+
import { readDockerCompose, writeDockerCompose } from './config';
|
|
6
6
|
import { isAppStarted, restartApp } from './status';
|
|
7
|
-
import {
|
|
7
|
+
import { buildApp, getAppDir, requireAppReady } from './utils';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Overrides the current environment variables specified in the
|
|
11
|
+
* docker-compose.yaml file.
|
|
12
|
+
*
|
|
13
|
+
* @param props.projectId - The project ID.
|
|
14
|
+
* @param props.envVars - The environment variables to override the
|
|
15
|
+
* ones currently in docker-compose.yaml
|
|
16
|
+
* @raises When called if there are no services in a docker-compose.yaml file
|
|
17
|
+
*/
|
|
18
|
+
export async function setEnvVars(props: {
|
|
10
19
|
projectId: string;
|
|
11
20
|
envVars: EnvVars;
|
|
12
21
|
}): Promise<void> {
|
|
@@ -18,7 +27,7 @@ export async function setEnv(props: {
|
|
|
18
27
|
projectId,
|
|
19
28
|
version: appReleaseHash
|
|
20
29
|
});
|
|
21
|
-
await
|
|
30
|
+
await setEnvVarsInternal({ projectId, envVars });
|
|
22
31
|
|
|
23
32
|
const appDir = getAppDir(projectId);
|
|
24
33
|
await buildApp({ appDir });
|
|
@@ -40,7 +49,18 @@ export async function setEnv(props: {
|
|
|
40
49
|
);
|
|
41
50
|
}
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Overrides the current environment variables specified in the
|
|
54
|
+
* docker-compose.yaml file. Intended for internal use only, as
|
|
55
|
+
* it does not check if there is an installation in progress
|
|
56
|
+
* before proceeding with the environment variable update.
|
|
57
|
+
*
|
|
58
|
+
* @param props.projectId - The project ID.
|
|
59
|
+
* @param props.envVars - The environment variables to override the
|
|
60
|
+
* ones currently in docker-compose.yaml
|
|
61
|
+
* @raises When called if there are no services in a docker-compose.yaml file
|
|
62
|
+
*/
|
|
63
|
+
export async function setEnvVarsInternal(props: {
|
|
44
64
|
projectId: string;
|
|
45
65
|
envVars: EnvVars;
|
|
46
66
|
}): Promise<void> {
|
|
@@ -76,7 +96,15 @@ export async function setEnvInternal(props: {
|
|
|
76
96
|
await writeDockerCompose({ projectId, dockerCompose: composeParsed });
|
|
77
97
|
}
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Converts a string array of environment variables into an iterable object,
|
|
101
|
+
* where each string is converted to a key-value pair.
|
|
102
|
+
*
|
|
103
|
+
* @param stringEnvs - Environment variables in the format of
|
|
104
|
+
* ['<variableName>=<variableValue>', '<variableName>=<variableValue>']
|
|
105
|
+
* @returns The variables as an object, as key-value pairs
|
|
106
|
+
*/
|
|
107
|
+
export function convertStringEnvsToKeyVal(stringEnvs: string[]): any {
|
|
80
108
|
const envVars = {};
|
|
81
109
|
stringEnvs.forEach((env: string) => {
|
|
82
110
|
const keyVal = env.split('=');
|
|
@@ -85,11 +113,34 @@ export function convertStringEnvsToKeyVal(stringEnvs: string[]) {
|
|
|
85
113
|
return envVars;
|
|
86
114
|
}
|
|
87
115
|
|
|
88
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Returns all environment variables for all services currently set
|
|
118
|
+
* in the docker-compose.yaml file.
|
|
119
|
+
*
|
|
120
|
+
* @param props.projectId - The project ID
|
|
121
|
+
* @raises When called if there are no services in a docker-compose.yaml file
|
|
122
|
+
*/
|
|
123
|
+
export async function getAllEnvVars(props: {
|
|
89
124
|
projectId: string;
|
|
90
125
|
}): Promise<EnvVars> {
|
|
91
126
|
const { projectId } = props;
|
|
92
127
|
await requireAppReady({ projectId });
|
|
128
|
+
return getAllEnvVarsInternal(props);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Returns all environment variables for all services currently set
|
|
133
|
+
* in the docker-compose.yaml file. Intended for internal use only, as
|
|
134
|
+
* it does not check if there is an installation in progress
|
|
135
|
+
* before proceeding with the environment variable lookup.
|
|
136
|
+
*
|
|
137
|
+
* @param props.projectId - The project ID
|
|
138
|
+
* @raises When called if there are no services in a docker-compose.yaml file
|
|
139
|
+
*/
|
|
140
|
+
export async function getAllEnvVarsInternal(props: {
|
|
141
|
+
projectId: string;
|
|
142
|
+
}): Promise<EnvVars> {
|
|
143
|
+
const { projectId } = props;
|
|
93
144
|
const appDir = getAppDir(projectId);
|
|
94
145
|
const spawner = JsSpawner({ path: appDir });
|
|
95
146
|
const envVars: EnvVars = {};
|
|
@@ -127,3 +178,34 @@ export async function getAllEnvs(props: {
|
|
|
127
178
|
}
|
|
128
179
|
return envVars;
|
|
129
180
|
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Adds new environment variables to the existing ones in the
|
|
184
|
+
* docker-compose.yaml file.
|
|
185
|
+
*
|
|
186
|
+
* @param props.projectId - The project ID.
|
|
187
|
+
* @param props.envVars - The environment variables to add to the
|
|
188
|
+
* docker-compose.yaml
|
|
189
|
+
* @raises When called if there are no services in a docker-compose.yaml file
|
|
190
|
+
*/
|
|
191
|
+
export async function updateEnvVarsInternal(props: {
|
|
192
|
+
projectId: string;
|
|
193
|
+
envVars: EnvVars;
|
|
194
|
+
}): Promise<void> {
|
|
195
|
+
const { projectId, envVars } = props;
|
|
196
|
+
const outputEnvVars = await getAllEnvVarsInternal({ projectId });
|
|
197
|
+
Object.keys(envVars).forEach((service) => {
|
|
198
|
+
if (service in outputEnvVars) {
|
|
199
|
+
// Merge and update existing env vars with new ones
|
|
200
|
+
outputEnvVars[service] = {
|
|
201
|
+
...outputEnvVars[service],
|
|
202
|
+
...envVars[service]
|
|
203
|
+
};
|
|
204
|
+
} else {
|
|
205
|
+
// Set env vars to new ones for service
|
|
206
|
+
outputEnvVars[service] = envVars[service];
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
logger.debug(`applying envVarUpdate: ${JSON.stringify(outputEnvVars)}`);
|
|
210
|
+
await setEnvVarsInternal({ projectId, envVars: outputEnvVars });
|
|
211
|
+
}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
+
import { rollbackApp } from './backup';
|
|
1
2
|
import { readAppCfgFile, updateAppCfg } from './config';
|
|
3
|
+
import { getAllEnvVars, setEnvVars } from './environment-variables';
|
|
2
4
|
import { installApp, uninstallApp } from './install';
|
|
3
|
-
import { rollbackApp } from './backup';
|
|
4
5
|
import {
|
|
6
|
+
getAppLogs,
|
|
5
7
|
getAppState,
|
|
8
|
+
restartApp,
|
|
6
9
|
startApp,
|
|
7
|
-
|
|
8
|
-
stopApp,
|
|
9
|
-
restartApp
|
|
10
|
+
stopApp
|
|
10
11
|
} from './status';
|
|
11
12
|
import { ModelDetails } from './types';
|
|
12
|
-
import { getAllEnvs, setEnv } from './environment-variables';
|
|
13
13
|
|
|
14
14
|
export {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
getAllEnvVars,
|
|
16
|
+
getAppLogs,
|
|
17
|
+
getAppState,
|
|
17
18
|
installApp,
|
|
18
|
-
|
|
19
|
+
ModelDetails,
|
|
20
|
+
readAppCfgFile,
|
|
21
|
+
restartApp,
|
|
19
22
|
rollbackApp,
|
|
20
|
-
|
|
23
|
+
setEnvVars,
|
|
21
24
|
startApp,
|
|
22
|
-
getAppLogs,
|
|
23
25
|
stopApp,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
getAllEnvs,
|
|
27
|
-
setEnv
|
|
26
|
+
uninstallApp,
|
|
27
|
+
updateAppCfg
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
// CLI-mode only
|
|
@@ -1,40 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as fs from 'fs';
|
|
3
|
-
import * as path from 'path';
|
|
4
|
-
import { buildDockerImage } from 'alwaysai/lib/util/docker';
|
|
5
|
-
import { JsSpawner, Spawner, stringifyError } from 'alwaysai/lib/util';
|
|
6
|
-
import { getAppDir, buildApp } from './utils';
|
|
1
|
+
import { AppConfig } from '@alwaysai/app-configuration-schemas';
|
|
7
2
|
import { AppDetails, EnvVars } from '@alwaysai/device-agent-schemas';
|
|
8
|
-
import {
|
|
9
|
-
import { startApp, stopApp, isAppStarted } from './status';
|
|
10
|
-
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
11
|
-
import { ProjectJsonFile } from 'alwaysai/lib/core/project';
|
|
3
|
+
import { DOCKER_IMAGE_ID_INITIAL_VALUE } from 'alwaysai/lib/constants';
|
|
12
4
|
import {
|
|
13
|
-
getTargetHardwareType,
|
|
14
|
-
AppJsonFile,
|
|
15
|
-
TargetJsonFile,
|
|
16
5
|
appCleanDocker,
|
|
17
|
-
|
|
6
|
+
AppJsonFile,
|
|
18
7
|
createPythonVenv,
|
|
8
|
+
getPythonVenvPaths,
|
|
9
|
+
getTargetHardwareType,
|
|
19
10
|
installPythonReqs,
|
|
20
|
-
TargetHardware
|
|
11
|
+
TargetHardware,
|
|
12
|
+
TargetJsonFile
|
|
21
13
|
} from 'alwaysai/lib/core/app';
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import
|
|
14
|
+
import { ProjectJsonFile } from 'alwaysai/lib/core/project';
|
|
15
|
+
import { DOCKERFILE, PYTHON_REQUIREMENTS_FILE_NAME } from 'alwaysai/lib/paths';
|
|
16
|
+
import { JsSpawner, Spawner, stringifyError } from 'alwaysai/lib/util';
|
|
17
|
+
import { buildDockerImage } from 'alwaysai/lib/util/docker';
|
|
18
|
+
import * as fs from 'fs';
|
|
19
|
+
import * as path from 'path';
|
|
20
|
+
import { rimraf } from 'rimraf';
|
|
21
|
+
import { ALWAYSAI_TARGET_HW_OVERRIDE, parseTargetHW } from '../environment';
|
|
22
|
+
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
27
23
|
import {
|
|
28
24
|
LOCAL_CONNECTION_HOST,
|
|
29
25
|
LOCAL_CONNECTION_PORT,
|
|
30
26
|
LOCAL_CONNECTION_ROUTING_KEY
|
|
31
27
|
} from '../local-connection/constants';
|
|
32
|
-
import { DOCKERFILE, PYTHON_REQUIREMENTS_FILE_NAME } from 'alwaysai/lib/paths';
|
|
33
28
|
import { downloadToFile } from '../util/file';
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
29
|
+
import { logger } from '../util/logger';
|
|
30
|
+
import { runInDir } from '../util/run-in-dir';
|
|
31
|
+
import { BACKUP_EXT } from './backup';
|
|
32
|
+
import { updateAppCfgFile, writeAppCfgFile } from './config';
|
|
33
|
+
import { updateEnvVarsAndPassthroughInternal } from './environment-variables-and-passthrough-update';
|
|
34
|
+
import { installModelsWithPresignedURLs } from './models';
|
|
35
|
+
import { isAppStarted, startApp, stopApp } from './status';
|
|
36
|
+
import { buildApp, getAppDir } from './utils';
|
|
38
37
|
|
|
39
38
|
type SignedUrlPayloadType = {
|
|
40
39
|
appInstallPayload: {
|
|
@@ -135,25 +134,28 @@ export async function installApp(props: {
|
|
|
135
134
|
path.join(appDir, 'models')
|
|
136
135
|
);
|
|
137
136
|
|
|
138
|
-
// See if there's appCfg
|
|
137
|
+
// See if there's appCfg in the transaction, and if so, apply it
|
|
138
|
+
// NOTE: this must be done before buildApp to ensure the changes
|
|
139
|
+
// are in the docker image
|
|
139
140
|
|
|
140
141
|
if (appCfg) {
|
|
141
142
|
logger.debug(`applying appCfg: ${JSON.stringify(appCfg)}`);
|
|
142
143
|
await writeAppCfgFile({ projectId, appCfg });
|
|
143
144
|
}
|
|
144
145
|
|
|
145
|
-
if (envVars) {
|
|
146
|
-
logger.debug(`applying envVarUpdate: ${JSON.stringify(envVars)}`);
|
|
147
|
-
try {
|
|
148
|
-
await setEnvInternal({ projectId, envVars });
|
|
149
|
-
} catch (error) {
|
|
150
|
-
logger.error(`error is : ${error}`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
146
|
await installAppBuildReqs({ appDir });
|
|
155
147
|
await buildApp({ appDir });
|
|
156
148
|
|
|
149
|
+
// Update environment variables if passed in to the install
|
|
150
|
+
// and/or if the pass-through is being used.
|
|
151
|
+
// We are doing this after the buildApp step to ensure that the
|
|
152
|
+
// docker-compose.yaml file exists when we update the environment variables.
|
|
153
|
+
// Since buildApp builds the images, and environment variables are added
|
|
154
|
+
// to the container, this flow works so long as updateEnvVarsInternal is
|
|
155
|
+
// called before startApp (or specifically running 'docker compose up').
|
|
156
|
+
|
|
157
|
+
await updateEnvVarsAndPassthroughInternal(projectId, envVars);
|
|
158
|
+
|
|
157
159
|
await AgentConfigFile().setAppInstalled({
|
|
158
160
|
projectId,
|
|
159
161
|
version: appReleaseHash
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { compose } from '../docker/docker-compose';
|
|
2
1
|
import * as path from 'path';
|
|
2
|
+
import { compose } from '../docker/docker-compose';
|
|
3
3
|
|
|
4
|
-
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
5
4
|
import {
|
|
6
5
|
getDockerComposeCmdForApp,
|
|
7
6
|
TargetJsonFile,
|
|
@@ -9,11 +8,12 @@ import {
|
|
|
9
8
|
writeDockerComposeFile,
|
|
10
9
|
writeStandaloneDockerfile
|
|
11
10
|
} from 'alwaysai/lib/core/app';
|
|
12
|
-
import { runInDir } from '../util/run-in-dir';
|
|
13
|
-
import { logger } from '../util/logger';
|
|
14
|
-
import { APP_ROOT } from '../util/directories';
|
|
15
|
-
import { JsSpawner } from 'alwaysai/lib/util/spawner';
|
|
16
11
|
import { DOCKER_COMPOSE_FILE, TARGET_JSON_FILE_NAME } from 'alwaysai/lib/paths';
|
|
12
|
+
import { JsSpawner } from 'alwaysai/lib/util/spawner';
|
|
13
|
+
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
14
|
+
import { APP_ROOT } from '../util/directories';
|
|
15
|
+
import { logger } from '../util/logger';
|
|
16
|
+
import { runInDir } from '../util/run-in-dir';
|
|
17
17
|
|
|
18
18
|
export function getAppDir(projectId: string): string {
|
|
19
19
|
return path.join(APP_ROOT, projectId);
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '@alwaysai/device-agent-schemas';
|
|
25
25
|
import {
|
|
26
26
|
AppInstallResponseMessage,
|
|
27
|
+
AppVersionControlUpdateConfigPayload,
|
|
27
28
|
ModelsInstallResponseMessage
|
|
28
29
|
} from '@alwaysai/device-agent-schemas/lib/app-action-schema';
|
|
29
30
|
import { DeviceActionMessage } from '@alwaysai/device-agent-schemas/lib/device-action-schema';
|
|
@@ -226,6 +227,7 @@ class AppVersionControlMessageHandler
|
|
|
226
227
|
private handleAppVersionControl = async (
|
|
227
228
|
payload:
|
|
228
229
|
| AppVersionControlInstallPayload
|
|
230
|
+
| AppVersionControlUpdateConfigPayload
|
|
229
231
|
| AppVersionControlUninstallPayload,
|
|
230
232
|
txId: string
|
|
231
233
|
): Promise<boolean> => {
|
|
@@ -24,18 +24,18 @@ import {
|
|
|
24
24
|
} from '@alwaysai/device-agent-schemas/lib/shadow-schema';
|
|
25
25
|
import { stringifyError } from 'alwaysai/lib/util';
|
|
26
26
|
import {
|
|
27
|
-
|
|
27
|
+
getAllEnvVars,
|
|
28
28
|
readAppCfgFile,
|
|
29
|
-
|
|
29
|
+
setEnvVars,
|
|
30
30
|
updateAppCfg
|
|
31
31
|
} from '../application-control';
|
|
32
|
+
import { pruneModels } from '../application-control/models';
|
|
32
33
|
import { getSystemInformation } from '../device-control/device-control';
|
|
33
34
|
import { logger } from '../util/logger';
|
|
35
|
+
import { BaseHandler } from './base-message-handler';
|
|
36
|
+
import { MessageHandler } from './message-dispatcher';
|
|
34
37
|
import { Publisher } from './publisher';
|
|
35
38
|
import { AppConfigModels, getAppCfgModelsDiff } from './shadow';
|
|
36
|
-
import { pruneModels } from '../application-control/models';
|
|
37
|
-
import { MessageHandler } from './message-dispatcher';
|
|
38
|
-
import { BaseHandler } from './base-message-handler';
|
|
39
39
|
|
|
40
40
|
export type AppConfigUpdate = {
|
|
41
41
|
newAppCfg: AppConfig;
|
|
@@ -365,7 +365,7 @@ export class ShadowHandler {
|
|
|
365
365
|
|
|
366
366
|
public async updateProjectShadow(projectId: string) {
|
|
367
367
|
const appCfg = await readAppCfgFile({ projectId });
|
|
368
|
-
const envVars = await
|
|
368
|
+
const envVars = await getAllEnvVars({ projectId });
|
|
369
369
|
|
|
370
370
|
const toReport: ShadowProjectsUpdateAll = {
|
|
371
371
|
[projectId]: {
|
|
@@ -391,8 +391,8 @@ export class ShadowHandler {
|
|
|
391
391
|
projectId: string;
|
|
392
392
|
envVars: EnvVars;
|
|
393
393
|
}) {
|
|
394
|
-
await
|
|
395
|
-
const currentEnvs = await
|
|
394
|
+
await setEnvVars({ projectId, envVars });
|
|
395
|
+
const currentEnvs = await getAllEnvVars({ projectId });
|
|
396
396
|
this.publisher.publish(
|
|
397
397
|
getShadowTopic(this.clientId, 'projects', 'update'),
|
|
398
398
|
JSON.stringify(
|
package/src/environment.ts
CHANGED
|
@@ -15,9 +15,10 @@ export const ALWAYSAI_LOG_TO_CONSOLE = process.env.ALWAYSAI_LOG_TO_CONSOLE;
|
|
|
15
15
|
export const ALWAYSAI_ANALYTICS_PASSTHROUGH = parseBoolean(
|
|
16
16
|
process.env.ALWAYSAI_ANALYTICS_PASSTHROUGH
|
|
17
17
|
);
|
|
18
|
+
export const ALWAYSAI_EDGEIQ_PASSTHROUGH_ENV_VAR_NAME =
|
|
19
|
+
process.env.ALWAYSAI_EDGEIQ_PASSTHROUGH_ENV_VAR_NAME;
|
|
18
20
|
export const ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS =
|
|
19
21
|
process.env.ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS;
|
|
20
|
-
|
|
21
22
|
export const ALWAYSAI_LOCAL_CONNECTION_HOST =
|
|
22
23
|
process.env.ALWAYSAI_LOCAL_CONNECTION_HOST;
|
|
23
24
|
export const ALWAYSAI_LOCAL_CONNECTION_PORT =
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ALWAYSAI_EDGEIQ_PASSTHROUGH_ENV_VAR_NAME,
|
|
3
|
+
ALWAYSAI_LOCAL_CONNECTION_ANALYTICS_ROUTING_KEY,
|
|
2
4
|
ALWAYSAI_LOCAL_CONNECTION_HOST,
|
|
3
|
-
ALWAYSAI_LOCAL_CONNECTION_PORT
|
|
4
|
-
ALWAYSAI_LOCAL_CONNECTION_ANALYTICS_ROUTING_KEY
|
|
5
|
+
ALWAYSAI_LOCAL_CONNECTION_PORT
|
|
5
6
|
} from '../environment';
|
|
6
7
|
|
|
7
8
|
export const LOCAL_CONNECTION_HOST = ALWAYSAI_LOCAL_CONNECTION_HOST
|
|
@@ -14,3 +15,7 @@ export const LOCAL_CONNECTION_ROUTING_KEY =
|
|
|
14
15
|
ALWAYSAI_LOCAL_CONNECTION_ANALYTICS_ROUTING_KEY
|
|
15
16
|
? ALWAYSAI_LOCAL_CONNECTION_ANALYTICS_ROUTING_KEY
|
|
16
17
|
: 'edgeiq-analytics-publish';
|
|
18
|
+
export const LOCAL_CONNECTION_PASSTHROUGH_ENV_VAR_NAME =
|
|
19
|
+
ALWAYSAI_EDGEIQ_PASSTHROUGH_ENV_VAR_NAME
|
|
20
|
+
? ALWAYSAI_EDGEIQ_PASSTHROUGH_ENV_VAR_NAME
|
|
21
|
+
: 'ALWAYSAI_CONNECT_TO_DEVICE_AGENT';
|