@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.
Files changed (58) hide show
  1. package/lib/application-control/config.d.ts.map +1 -1
  2. package/lib/application-control/config.js +7 -7
  3. package/lib/application-control/config.js.map +1 -1
  4. package/lib/application-control/environment-variables-and-passthrough-update.d.ts +15 -0
  5. package/lib/application-control/environment-variables-and-passthrough-update.d.ts.map +1 -0
  6. package/lib/application-control/environment-variables-and-passthrough-update.js +46 -0
  7. package/lib/application-control/environment-variables-and-passthrough-update.js.map +1 -0
  8. package/lib/application-control/environment-variables-and-passthrough-update.test.d.ts +2 -0
  9. package/lib/application-control/environment-variables-and-passthrough-update.test.d.ts.map +1 -0
  10. package/lib/application-control/environment-variables-and-passthrough-update.test.js +188 -0
  11. package/lib/application-control/environment-variables-and-passthrough-update.test.js.map +1 -0
  12. package/lib/application-control/environment-variables.d.ts +64 -4
  13. package/lib/application-control/environment-variables.d.ts.map +1 -1
  14. package/lib/application-control/environment-variables.js +86 -11
  15. package/lib/application-control/environment-variables.js.map +1 -1
  16. package/lib/application-control/environment-variables.test.js +156 -10
  17. package/lib/application-control/environment-variables.test.js.map +1 -1
  18. package/lib/application-control/index.d.ts +4 -4
  19. package/lib/application-control/index.d.ts.map +1 -1
  20. package/lib/application-control/index.js +8 -8
  21. package/lib/application-control/index.js.map +1 -1
  22. package/lib/application-control/install.d.ts +1 -1
  23. package/lib/application-control/install.d.ts.map +1 -1
  24. package/lib/application-control/install.js +27 -26
  25. package/lib/application-control/install.js.map +1 -1
  26. package/lib/application-control/utils.js +6 -6
  27. package/lib/application-control/utils.js.map +1 -1
  28. package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -1
  29. package/lib/cloud-connection/device-agent-message-handler.js.map +1 -1
  30. package/lib/cloud-connection/shadow-handler.d.ts +2 -2
  31. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  32. package/lib/cloud-connection/shadow-handler.js +5 -5
  33. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  34. package/lib/environment.d.ts +1 -0
  35. package/lib/environment.d.ts.map +1 -1
  36. package/lib/environment.js +2 -1
  37. package/lib/environment.js.map +1 -1
  38. package/lib/local-connection/constants.d.ts +1 -0
  39. package/lib/local-connection/constants.d.ts.map +1 -1
  40. package/lib/local-connection/constants.js +4 -1
  41. package/lib/local-connection/constants.js.map +1 -1
  42. package/lib/subcommands/app/env-vars.js +4 -4
  43. package/lib/subcommands/app/env-vars.js.map +1 -1
  44. package/package.json +3 -3
  45. package/readme.md +1 -1
  46. package/src/application-control/config.ts +9 -9
  47. package/src/application-control/environment-variables-and-passthrough-update.test.ts +221 -0
  48. package/src/application-control/environment-variables-and-passthrough-update.ts +56 -0
  49. package/src/application-control/environment-variables.test.ts +168 -12
  50. package/src/application-control/environment-variables.ts +91 -9
  51. package/src/application-control/index.ts +14 -14
  52. package/src/application-control/install.ts +37 -35
  53. package/src/application-control/utils.ts +6 -6
  54. package/src/cloud-connection/device-agent-message-handler.ts +2 -0
  55. package/src/cloud-connection/shadow-handler.ts +8 -8
  56. package/src/environment.ts +2 -1
  57. package/src/local-connection/constants.ts +7 -2
  58. 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
- getAllEnvs,
6
- setEnv
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 getAllEnvs()', () => {
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 getAllEnvs({ projectId: projectId1 });
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 getAllEnvs({ projectId: projectId1 });
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 getAllEnvs({ projectId: projectId1 });
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 getAllEnvs({ projectId: projectId1 });
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 setEnv()', () => {
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 setEnv({ projectId: projectId1, envVars });
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 setEnv({ projectId: projectId1, envVars });
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 setEnv({ projectId: projectId1, envVars });
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 setEnv({ projectId: projectId1, envVars });
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 { EnvVars } from '@alwaysai/device-agent-schemas';
7
+ import { buildApp, getAppDir, requireAppReady } from './utils';
8
8
 
9
- export async function setEnv(props: {
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 setEnvInternal({ projectId, envVars });
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
- export async function setEnvInternal(props: {
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
- export function convertStringEnvsToKeyVal(stringEnvs: string[]) {
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
- export async function getAllEnvs(props: {
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
- getAppLogs,
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
- readAppCfgFile,
16
- updateAppCfg,
15
+ getAllEnvVars,
16
+ getAppLogs,
17
+ getAppState,
17
18
  installApp,
18
- uninstallApp,
19
+ ModelDetails,
20
+ readAppCfgFile,
21
+ restartApp,
19
22
  rollbackApp,
20
- getAppState,
23
+ setEnvVars,
21
24
  startApp,
22
- getAppLogs,
23
25
  stopApp,
24
- restartApp,
25
- ModelDetails,
26
- getAllEnvs,
27
- setEnv
26
+ uninstallApp,
27
+ updateAppCfg
28
28
  };
29
29
 
30
30
  // CLI-mode only
@@ -1,40 +1,39 @@
1
- import { rimraf } from 'rimraf';
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 { BACKUP_EXT } from './backup';
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
- getPythonVenvPaths,
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 { DOCKER_IMAGE_ID_INITIAL_VALUE } from 'alwaysai/lib/constants';
23
- import { runInDir } from '../util/run-in-dir';
24
- import { installModelsWithPresignedURLs } from './models';
25
- import { logger } from '../util/logger';
26
- import { updateAppCfgFile, writeAppCfgFile } from './config';
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 { ALWAYSAI_TARGET_HW_OVERRIDE, parseTargetHW } from '../environment';
35
- import { setEnvInternal } from './environment-variables';
36
- import { AppConfig } from '@alwaysai/app-configuration-schemas';
37
- import { CliTerseError } from '@alwaysai/alwayscli';
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 or envVars in the transaction, and if so, apply it
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
- getAllEnvs,
27
+ getAllEnvVars,
28
28
  readAppCfgFile,
29
- setEnv,
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 getAllEnvs({ projectId });
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 setEnv({ projectId, envVars });
395
- const currentEnvs = await getAllEnvs({ projectId });
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(
@@ -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';