@bitblit/ratchet-aws 4.0.115-alpha → 4.0.116-alpha

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 (119) hide show
  1. package/lib/cloudwatch/cloud-watch-log-group-ratchet.d.ts +1 -0
  2. package/lib/cloudwatch/cloud-watch-logs-ratchet.d.ts +1 -0
  3. package/lib/cloudwatch/cloud-watch-metrics-ratchet.d.ts +1 -0
  4. package/lib/daemon/daemon-like.d.ts +1 -1
  5. package/lib/daemon/daemon-util.d.ts +2 -2
  6. package/lib/daemon/daemon.d.ts +1 -1
  7. package/lib/dynamodb/dynamo-ratchet.d.ts +1 -0
  8. package/lib/ec2/ec2-ratchet.d.ts +4 -2
  9. package/lib/index.d.ts +78 -1
  10. package/lib/index.mjs +10 -0
  11. package/lib/index.mjs.map +1 -0
  12. package/lib/route53/route-53-ratchet.d.ts +1 -0
  13. package/lib/s3/s3-cache-ratchet.d.ts +3 -2
  14. package/lib/s3/s3-cache-to-local-disk-ratchet.d.ts +1 -1
  15. package/lib/ses/mailer.d.ts +1 -0
  16. package/lib/sns/sns-ratchet.d.ts +1 -0
  17. package/package.json +25 -84
  18. package/lib/batch/aws-batch-background-processor.js +0 -45
  19. package/lib/batch/aws-batch-background-processor.spec.js +0 -15
  20. package/lib/batch/aws-batch-ratchet.js +0 -55
  21. package/lib/batch/aws-batch-ratchet.spec.js +0 -33
  22. package/lib/build/ratchet-aws-info.js +0 -14
  23. package/lib/cache/dynamo-db-storage-provider.js +0 -109
  24. package/lib/cache/s3-storage-provider.js +0 -43
  25. package/lib/cache/simple-cache-object-wrapper.js +0 -1
  26. package/lib/cache/simple-cache-read-options.js +0 -1
  27. package/lib/cache/simple-cache-storage-provider.js +0 -1
  28. package/lib/cache/simple-cache.js +0 -64
  29. package/lib/cache/simple-cache.spec.js +0 -67
  30. package/lib/cloudwatch/cloud-watch-log-group-ratchet.js +0 -71
  31. package/lib/cloudwatch/cloud-watch-log-group-ratchet.spec.js +0 -19
  32. package/lib/cloudwatch/cloud-watch-logs-ratchet.js +0 -170
  33. package/lib/cloudwatch/cloud-watch-logs-ratchet.spec.js +0 -84
  34. package/lib/cloudwatch/cloud-watch-metrics-ratchet.js +0 -54
  35. package/lib/cloudwatch/cloud-watch-metrics-ratchet.spec.js +0 -23
  36. package/lib/daemon/daemon-like.js +0 -1
  37. package/lib/daemon/daemon-process-create-options.js +0 -1
  38. package/lib/daemon/daemon-process-state-public-token.js +0 -1
  39. package/lib/daemon/daemon-process-state.js +0 -1
  40. package/lib/daemon/daemon-util.js +0 -148
  41. package/lib/daemon/daemon-util.spec.js +0 -79
  42. package/lib/daemon/daemon.js +0 -128
  43. package/lib/dao/prototype-dao-config.js +0 -1
  44. package/lib/dao/prototype-dao-db.js +0 -1
  45. package/lib/dao/prototype-dao-provider.js +0 -1
  46. package/lib/dao/prototype-dao.js +0 -88
  47. package/lib/dao/prototype-dao.spec.js +0 -26
  48. package/lib/dao/s3-prototype-dao-provider.js +0 -26
  49. package/lib/dao/s3-simple-dao.js +0 -76
  50. package/lib/dao/simple-dao-item.js +0 -1
  51. package/lib/dynamodb/dynamo-ratchet-like.js +0 -1
  52. package/lib/dynamodb/dynamo-ratchet.js +0 -666
  53. package/lib/dynamodb/dynamo-ratchet.spec.js +0 -156
  54. package/lib/dynamodb/dynamo-table-ratchet.js +0 -88
  55. package/lib/dynamodb/hash-spreader.js +0 -65
  56. package/lib/dynamodb/hash-spreader.spec.js +0 -17
  57. package/lib/ec2/ec2-ratchet.js +0 -107
  58. package/lib/ec2/ec2-ratchet.spec.js +0 -31
  59. package/lib/environment/cascade-environment-service-provider.js +0 -24
  60. package/lib/environment/env-var-environment-service-provider.js +0 -30
  61. package/lib/environment/environment-service-config.js +0 -1
  62. package/lib/environment/environment-service-provider.js +0 -1
  63. package/lib/environment/environment-service.js +0 -50
  64. package/lib/environment/environment-service.spec.js +0 -22
  65. package/lib/environment/fixed-environment-service-provider.js +0 -21
  66. package/lib/environment/s3-environment-service-provider.js +0 -27
  67. package/lib/environment/ssm-environment-service-provider.js +0 -59
  68. package/lib/expiring-code/dynamo-expiring-code-provider.js +0 -24
  69. package/lib/expiring-code/expiring-code-params.js +0 -1
  70. package/lib/expiring-code/expiring-code-provider.js +0 -1
  71. package/lib/expiring-code/expiring-code-ratchet.js +0 -34
  72. package/lib/expiring-code/expiring-code-ratchet.spec.js +0 -7
  73. package/lib/expiring-code/expiring-code.js +0 -1
  74. package/lib/expiring-code/s3-expiring-code-provider.js +0 -48
  75. package/lib/expiring-code/s3-expiring-code-provider.spec.js +0 -46
  76. package/lib/iam/aws-credentials-ratchet.js +0 -18
  77. package/lib/index.js +0 -1
  78. package/lib/lambda/lambda-event-detector.js +0 -38
  79. package/lib/lambda/lambda-event-type-guards.js +0 -24
  80. package/lib/model/cloud-watch-metrics-minute-level-dynamo-count-request.js +0 -1
  81. package/lib/model/cloud-watch-metrics-unit.js +0 -30
  82. package/lib/model/dynamo/doc-put-item-command-input.js +0 -1
  83. package/lib/model/dynamo/doc-query-command-input.js +0 -1
  84. package/lib/model/dynamo/doc-scan-command-input.js +0 -1
  85. package/lib/model/dynamo/doc-update-item-command-input.js +0 -1
  86. package/lib/model/dynamo-count-result.js +0 -1
  87. package/lib/route53/route-53-ratchet.js +0 -55
  88. package/lib/runtime-parameter/cached-stored-runtime-parameter.js +0 -1
  89. package/lib/runtime-parameter/dynamo-runtime-parameter-provider.js +0 -36
  90. package/lib/runtime-parameter/dynamo-runtime-parameter-provider.spec.js +0 -49
  91. package/lib/runtime-parameter/global-variable-override-runtime-parameter-provider.js +0 -51
  92. package/lib/runtime-parameter/global-variable-override-runtime-parameter-provider.spec.js +0 -37
  93. package/lib/runtime-parameter/memory-runtime-parameter-provider.js +0 -27
  94. package/lib/runtime-parameter/runtime-parameter-provider.js +0 -1
  95. package/lib/runtime-parameter/runtime-parameter-ratchet.js +0 -71
  96. package/lib/runtime-parameter/runtime-parameter-ratchet.spec.js +0 -39
  97. package/lib/runtime-parameter/stored-runtime-parameter.js +0 -1
  98. package/lib/s3/s3-cache-ratchet.js +0 -330
  99. package/lib/s3/s3-cache-ratchet.spec.js +0 -97
  100. package/lib/s3/s3-cache-to-local-disk-ratchet.js +0 -105
  101. package/lib/s3/s3-cache-to-local-dist-ratchet.spec.js +0 -22
  102. package/lib/s3/s3-location-sync-ratchet.js +0 -140
  103. package/lib/s3/s3-ratchet.js +0 -22
  104. package/lib/s3/s3-ratchet.spec.js +0 -20
  105. package/lib/ses/email-attachment.js +0 -1
  106. package/lib/ses/mailer-config.js +0 -1
  107. package/lib/ses/mailer-like.js +0 -1
  108. package/lib/ses/mailer.js +0 -206
  109. package/lib/ses/mailer.spec.js +0 -104
  110. package/lib/ses/ratchet-template-renderer.js +0 -1
  111. package/lib/ses/ready-to-send-email.js +0 -1
  112. package/lib/ses/remote-handlebars-template-renderer.js +0 -78
  113. package/lib/ses/resolved-ready-to-send-email.js +0 -1
  114. package/lib/sns/sns-ratchet.js +0 -45
  115. package/lib/sns/sns-ratchet.spec.js +0 -17
  116. package/lib/sync-lock/dynamo-db-sync-lock.js +0 -69
  117. package/lib/sync-lock/dynamo-db-sync-lock.spec.js +0 -30
  118. package/lib/sync-lock/memory-sync-lock.js +0 -35
  119. package/lib/sync-lock/sync-lock-provider.js +0 -1
@@ -1,156 +0,0 @@
1
- import { DynamoRatchet } from './dynamo-ratchet.js';
2
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
3
- import { LoggerLevelName } from '@bitblit/ratchet-common/lib/logger/logger-level-name.js';
4
- import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
5
- import { mockClient } from 'aws-sdk-client-mock';
6
- let mockDynamo;
7
- describe('#dynamoRatchet', function () {
8
- mockDynamo = mockClient(DynamoDBDocumentClient);
9
- beforeEach(() => {
10
- mockDynamo.reset();
11
- });
12
- xit('should handle ProvisionedThroughputExceeded exceptions', async () => {
13
- const dr = new DynamoRatchet(mockDynamo);
14
- let row = 0;
15
- const scan = {
16
- TableName: 'cache-device-data',
17
- ProjectionExpression: 'compositeKey',
18
- };
19
- Logger.info('Starting scan');
20
- const cnt = await dr.fullyExecuteProcessOverScan(scan, async (ob) => {
21
- if (row % 100 === 0) {
22
- Logger.info('Row : %d : %j', row, ob);
23
- }
24
- row++;
25
- });
26
- Logger.info('Count was : %d', cnt);
27
- }, 300_000_000);
28
- xit('should only write if a field is null', async () => {
29
- const dr = new DynamoRatchet(mockDynamo);
30
- const tableName = 'some-table';
31
- const test1 = { lockingKey: 'aaa', xx: null };
32
- await dr.simplePut(tableName, test1);
33
- const test2 = { lockingKey: 'aaa', xx: 5 };
34
- const val1 = await dr.simplePutOnlyIfFieldIsNullOrUndefined(tableName, test2, 'xx');
35
- expect(val1).toBeTruthy();
36
- const test3 = { lockingKey: 'aaa', xx: 7 };
37
- const val2 = await dr.simplePutOnlyIfFieldIsNullOrUndefined(tableName, test3, 'xx');
38
- expect(val2).toBeFalsy();
39
- });
40
- xit('should fetch items from a key-only index query', async () => {
41
- const dr = new DynamoRatchet(mockDynamo);
42
- const tableName = 'some-table';
43
- const limit = 200;
44
- const qry = {
45
- TableName: tableName,
46
- IndexName: 'purchaseId-notBeforeEpochMS-index',
47
- KeyConditionExpression: 'purchaseId = :purchaseId',
48
- Limit: limit,
49
- ExpressionAttributeValues: {
50
- ':purchaseId': 'some-purchase',
51
- },
52
- };
53
- const res = await dr.fetchFullObjectsMatchingKeysOnlyIndexQuery(qry, ['key1', 'key2']);
54
- Logger.info('Got : %s', res);
55
- expect(res).toBeTruthy();
56
- });
57
- xit('should increment the counter and return the new value', async () => {
58
- const dr = new DynamoRatchet(mockDynamo);
59
- const tableName = 'xxx';
60
- const res = await dr.atomicCounter(tableName, { groupId: 'global', unitId: 'sequence' }, 'lastValue', 1);
61
- Logger.info('Got : %s', res);
62
- expect(res).toBeTruthy();
63
- });
64
- xit('should stop after the soft limit', async () => {
65
- const dr = new DynamoRatchet(mockDynamo);
66
- const now = new Date().getTime();
67
- const nowSec = Math.floor(now / 1000);
68
- const curHash = 'someHash';
69
- const qry = {
70
- TableName: 'some-table',
71
- KeyConditionExpression: 'hashVal = :hashVal',
72
- ExpressionAttributeValues: {
73
- ':hashVal': curHash,
74
- },
75
- };
76
- const res = await dr.fullyExecuteQuery(qry, null, 150);
77
- Logger.info('Got : %s', res);
78
- expect(res).toBeTruthy();
79
- }, 300_000);
80
- xit('should run an insert / read test for slowdown', async () => {
81
- const dr = new DynamoRatchet(mockDynamo);
82
- Logger.setLevel(LoggerLevelName.debug);
83
- const now = new Date().getTime();
84
- const nowSec = Math.floor(now / 1000);
85
- const nums = [];
86
- for (let i = 0; i < 300; i++) {
87
- const toWrite = {
88
- id: 'CW_DDB_TEST',
89
- data: 'SOME DATA',
90
- numData: i,
91
- };
92
- nums.push(toWrite);
93
- }
94
- Logger.info('About to start');
95
- const writeProms = nums.map((n) => dr.simplePut('some-table', n));
96
- const writeOut = await Promise.all(writeProms);
97
- Logger.info('Write : %j', writeOut);
98
- const readProms = [];
99
- Logger.info('Start : %d', new Date().getTime());
100
- for (let i = 0; i < 10000; i++) {
101
- readProms.push(dr.simpleGet('some-table', { id: 'CW_DDB_TEST' }));
102
- }
103
- Logger.info('Mid : %d', new Date().getTime());
104
- const readOut = await Promise.all(readProms);
105
- Logger.info('Read : %d : %j', new Date().getTime(), readOut);
106
- });
107
- xit('should run a collision test', async () => {
108
- const dr = new DynamoRatchet(mockDynamo);
109
- Logger.setLevel(LoggerLevelName.debug);
110
- const val = {
111
- k1: 'abc',
112
- k2: 1,
113
- };
114
- for (let i = 0; i < 5; i++) {
115
- const rval = await dr.simplePutWithCollisionAvoidance('cwtest', val, ['k1', 'k2'], (v) => {
116
- v.k2++;
117
- return v;
118
- }, null, 3);
119
- Logger.info('output was : %j', rval);
120
- }
121
- });
122
- xit('should do a simple get with counter decrement', async () => {
123
- const dr = new DynamoRatchet(mockDynamo);
124
- Logger.setLevel(LoggerLevelName.debug);
125
- const v = await dr.simpleGetWithCounterDecrement('cwtest', { k1: 'abc', k2: 11 }, 'counter', true);
126
- Logger.info('Got : %j', v);
127
- });
128
- xit('should do a full query', async () => {
129
- const dr = new DynamoRatchet(mockDynamo);
130
- Logger.setLevel(LoggerLevelName.debug);
131
- const input = {
132
- TableName: 'some-table',
133
- KeyConditionExpression: 'groupId = :g',
134
- ExpressionAttributeValues: {
135
- ':g': 'NeonBatch',
136
- },
137
- };
138
- const res = await dr.fullyExecuteQuery(input);
139
- Logger.info('Got : %j', res);
140
- });
141
- xit('should do a process over full query', async () => {
142
- const dr = new DynamoRatchet(mockDynamo);
143
- Logger.setLevel(LoggerLevelName.debug);
144
- const input = {
145
- TableName: 'some-table',
146
- KeyConditionExpression: 'groupId = :g',
147
- ExpressionAttributeValues: {
148
- ':g': 'NeonBatch',
149
- },
150
- };
151
- const res = await dr.fullyExecuteProcessOverQuery(input, async (v) => {
152
- Logger.info('Proc %j', v);
153
- });
154
- Logger.info('Got : %j', res);
155
- });
156
- });
@@ -1,88 +0,0 @@
1
- import { CreateTableCommand, DeleteTableCommand, DescribeTableCommand, } from '@aws-sdk/client-dynamodb';
2
- import { ErrorRatchet } from '@bitblit/ratchet-common/lib/lang/error-ratchet.js';
3
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
4
- import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
5
- import { PromiseRatchet } from '@bitblit/ratchet-common/lib/lang/promise-ratchet.js';
6
- export class DynamoTableRatchet {
7
- awsDDB;
8
- constructor(awsDDB) {
9
- this.awsDDB = awsDDB;
10
- if (!awsDDB) {
11
- throw 'awsDDB may not be null';
12
- }
13
- }
14
- async deleteTable(tableName, waitForDelete = true) {
15
- RequireRatchet.notNullOrUndefined(tableName);
16
- const input = {
17
- TableName: tableName,
18
- };
19
- Logger.debug('Deleting ddb table %s', tableName);
20
- const rval = await this.awsDDB.send(new DeleteTableCommand(input));
21
- if (waitForDelete) {
22
- Logger.debug('Table marked for delete, waiting for deletion');
23
- await this.waitForTableDelete(tableName);
24
- }
25
- return rval;
26
- }
27
- async createTable(input, waitForReady = true, replaceIfExists = false) {
28
- RequireRatchet.notNullOrUndefined(input);
29
- RequireRatchet.notNullOrUndefined(input.TableName);
30
- Logger.debug('Creating new table : %j', input);
31
- const exists = await this.tableExists(input.TableName);
32
- if (exists) {
33
- if (replaceIfExists) {
34
- Logger.debug('Table %s exists and replace specified - deleting', input.TableName);
35
- await this.deleteTable(input.TableName);
36
- }
37
- else {
38
- ErrorRatchet.throwFormattedErr('Cannot create table %s - exists already and replace not specified', input.TableName);
39
- }
40
- }
41
- const rval = await this.awsDDB.send(new CreateTableCommand(input));
42
- if (waitForReady) {
43
- Logger.debug('Table created, awaiting ready');
44
- await this.waitForTableReady(input.TableName);
45
- }
46
- return rval;
47
- }
48
- async waitForTableReady(tableName) {
49
- let rval = true;
50
- let out = await this.safeDescribeTable(tableName);
51
- while (!!out && !!out.Table && out.Table.TableStatus !== 'ACTIVE') {
52
- Logger.silly('Table not ready - waiting 2 seconds');
53
- await PromiseRatchet.wait(2000);
54
- out = await this.safeDescribeTable(tableName);
55
- }
56
- if (!out && !out.Table) {
57
- Logger.warn('Cannot wait for %s to be ready - table does not exist', tableName);
58
- rval = false;
59
- }
60
- return rval;
61
- }
62
- async waitForTableDelete(tableName) {
63
- let out = await this.safeDescribeTable(tableName);
64
- while (!!out) {
65
- Logger.silly('Table %s still exists, waiting 2 seconds (State is %s)', tableName, out.Table.TableStatus);
66
- await PromiseRatchet.wait(2000);
67
- out = await this.safeDescribeTable(tableName);
68
- }
69
- }
70
- async tableExists(tableName) {
71
- const desc = await this.safeDescribeTable(tableName);
72
- return !!desc;
73
- }
74
- async safeDescribeTable(tableName) {
75
- try {
76
- const out = await this.awsDDB.send(new DescribeTableCommand({ TableName: tableName }));
77
- return out;
78
- }
79
- catch (err) {
80
- if (!!err['code'] && err['code'] === 'ResourceNotFoundException') {
81
- return null;
82
- }
83
- else {
84
- throw err;
85
- }
86
- }
87
- }
88
- }
@@ -1,65 +0,0 @@
1
- import { ErrorRatchet } from '@bitblit/ratchet-common/lib/lang/error-ratchet.js';
2
- import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
3
- import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
4
- export class HashSpreader {
5
- spots;
6
- buckets;
7
- separator;
8
- alphabet;
9
- _allSlots;
10
- constructor(spots = 3, buckets = 16, separator = '_', alphabet = '0123456789ABCDEF') {
11
- this.spots = spots;
12
- this.buckets = buckets;
13
- this.separator = separator;
14
- this.alphabet = alphabet;
15
- RequireRatchet.true(spots > 0, 'Spots must be larger than 0');
16
- RequireRatchet.true(buckets > 1, 'Buckets must be larger than 1');
17
- RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(alphabet), 'Alphabet may not be null or empty');
18
- RequireRatchet.true(StringRatchet.allUnique(alphabet), 'Alphabet must be unique');
19
- RequireRatchet.true(StringRatchet.stringContainsOnlyAlphanumeric(alphabet), 'Alphabet must be alphanumeric');
20
- const permutations = Math.pow(alphabet.length, spots);
21
- RequireRatchet.true(buckets < permutations, 'Buckets must be less than permutations (' + buckets + ' / ' + permutations + ')');
22
- RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(this.separator), 'Separator must be nonnull and nonempty');
23
- const allPerms = StringRatchet.allPermutationsOfLength(spots, alphabet);
24
- this._allSlots = allPerms.slice(0, buckets);
25
- }
26
- get allBuckets() {
27
- return Object.assign([], this._allSlots);
28
- }
29
- get randomBucket() {
30
- return this._allSlots[Math.floor(Math.random() * this.buckets)];
31
- }
32
- allSpreadValues(input) {
33
- RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(input), 'Cannot spread null/empty value');
34
- const rval = this._allSlots.map((s) => input + this.separator + s);
35
- return rval;
36
- }
37
- allSpreadValuesForArray(inputs) {
38
- RequireRatchet.true(inputs && inputs.length > 0, 'Cannot spread null/empty array');
39
- let rval = [];
40
- inputs.forEach((i) => {
41
- rval = rval.concat(this.allSpreadValues(i));
42
- });
43
- return rval;
44
- }
45
- addSpreader(input) {
46
- RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(input), 'Cannot spread null/empty value');
47
- return input + this.separator + this.randomBucket;
48
- }
49
- extractBucket(input) {
50
- RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(input), 'Cannot extract from null or empty value');
51
- const loc = input.length - this.spots;
52
- if (loc < 0 || input.charAt(loc) !== this.separator) {
53
- ErrorRatchet.throwFormattedErr('Cannot extract bucket, not created by this spreader (missing %s at location %d)', this.separator, loc);
54
- }
55
- return input.substring(loc);
56
- }
57
- removeBucket(input) {
58
- RequireRatchet.notNullOrUndefined(StringRatchet.trimToNull(input), 'Cannot extract from null or empty value');
59
- const loc = input.length - this.spots;
60
- if (loc < 0 || input.charAt(loc) !== this.separator) {
61
- ErrorRatchet.throwFormattedErr('Cannot remove bucket, not created by this spreader (missing %s at location %d)', this.separator, loc);
62
- }
63
- return input.substring(0, loc);
64
- }
65
- }
@@ -1,17 +0,0 @@
1
- import { HashSpreader } from './hash-spreader.js';
2
- describe('#hashSpreader', function () {
3
- it('should enumerate spread', async () => {
4
- const spread = new HashSpreader(3, 16);
5
- expect(spread.allBuckets.length).toEqual(16);
6
- const spread2 = new HashSpreader(3, 19);
7
- expect(spread2.allBuckets.length).toEqual(19);
8
- });
9
- it('should spread1', async () => {
10
- const spread = new HashSpreader(3, 16);
11
- expect(spread.allSpreadValues('x').length).toEqual(16);
12
- });
13
- it('should spread multi', async () => {
14
- const spread = new HashSpreader(3, 16);
15
- expect(spread.allSpreadValuesForArray(['x', 'y']).length).toEqual(32);
16
- });
17
- });
@@ -1,107 +0,0 @@
1
- import { DescribeInstancesCommand, EC2Client, StartInstancesCommand, StopInstancesCommand, } from '@aws-sdk/client-ec2';
2
- import { EC2InstanceConnectClient, SendSSHPublicKeyCommand, } from '@aws-sdk/client-ec2-instance-connect';
3
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
4
- import { PromiseRatchet } from '@bitblit/ratchet-common/lib/lang/promise-ratchet.js';
5
- import { DurationRatchet } from '@bitblit/ratchet-common/lib/lang/duration-ratchet.js';
6
- export class Ec2Ratchet {
7
- region;
8
- availabilityZone;
9
- ec2;
10
- ec2InstanceConnect;
11
- constructor(region = 'us-east-1', availabilityZone = 'us-east-1a') {
12
- this.region = region;
13
- this.availabilityZone = availabilityZone;
14
- this.ec2 = new EC2Client({ region: region });
15
- this.ec2InstanceConnect = new EC2InstanceConnectClient({ region: region });
16
- }
17
- async stopInstance(instanceId, maxWaitForShutdownMS = 0) {
18
- let rval = true;
19
- try {
20
- const stopParams = {
21
- InstanceIds: [instanceId],
22
- DryRun: false,
23
- };
24
- Logger.info('About to stop instances : %j', stopParams);
25
- await this.ec2.send(new StopInstancesCommand(stopParams));
26
- Logger.info('Stop instance command sent, waiting on shutdown');
27
- let status = await this.describeInstance(instanceId);
28
- if (maxWaitForShutdownMS > 0) {
29
- const start = new Date().getTime();
30
- while (!!status && status.State.Code !== 16 && new Date().getTime() - start < maxWaitForShutdownMS) {
31
- Logger.debug('Instance status is %j - waiting for 5 seconds (up to %s)', status.State, DurationRatchet.formatMsDuration(maxWaitForShutdownMS));
32
- await PromiseRatchet.wait(5000);
33
- status = await this.describeInstance(instanceId);
34
- }
35
- }
36
- }
37
- catch (err) {
38
- Logger.error('Failed to stop instance %s : %s', instanceId, err, err);
39
- rval = false;
40
- }
41
- return rval;
42
- }
43
- async launchInstance(instanceId, maxWaitForStartupMS = 0) {
44
- let rval = true;
45
- try {
46
- const startParams = {
47
- InstanceIds: [instanceId],
48
- DryRun: false,
49
- };
50
- Logger.info('About to start instance : %j', startParams);
51
- await this.ec2.send(new StartInstancesCommand(startParams));
52
- Logger.info('Start instance command sent, waiting on startup');
53
- let status = await this.describeInstance(instanceId);
54
- if (maxWaitForStartupMS > 0) {
55
- const start = new Date().getTime();
56
- while (!!status && status.State.Code !== 16 && new Date().getTime() - start < maxWaitForStartupMS) {
57
- Logger.debug('Instance status is %j - waiting for 5 seconds (up to %s)', status.State, DurationRatchet.formatMsDuration(maxWaitForStartupMS));
58
- await PromiseRatchet.wait(5000);
59
- status = await this.describeInstance(instanceId);
60
- }
61
- }
62
- if (!!status && !!status.PublicIpAddress) {
63
- Logger.info('Instance address is %s', status.PublicIpAddress);
64
- Logger.info('SSH command : ssh -i path_to_pem_file ec2-user@%s', status.PublicIpAddress);
65
- }
66
- }
67
- catch (err) {
68
- Logger.error('Failed to start instance %s : %s', instanceId, err, err);
69
- rval = false;
70
- }
71
- return rval;
72
- }
73
- async describeInstance(instanceId) {
74
- const res = await this.listAllInstances([instanceId]);
75
- return res.length === 1 ? res[0] : null;
76
- }
77
- async listAllInstances(instanceIds = []) {
78
- let rval = [];
79
- const req = {
80
- NextToken: null,
81
- };
82
- if (instanceIds && instanceIds.length > 0) {
83
- req.InstanceIds = instanceIds;
84
- }
85
- do {
86
- Logger.debug('Pulling instances... (%j)', req);
87
- const res = await this.ec2.send(new DescribeInstancesCommand(req));
88
- res.Reservations.forEach((r) => {
89
- rval = rval.concat(r.Instances);
90
- });
91
- req.NextToken = res.NextToken;
92
- } while (req.NextToken);
93
- Logger.debug('Finished pulling instances (found %d)', rval.length);
94
- return rval;
95
- }
96
- async sendPublicKeyToEc2Instance(instanceId, publicKeyString, instanceOsUser) {
97
- const userName = instanceOsUser || 'ec2-user';
98
- const req = {
99
- InstanceId: instanceId,
100
- AvailabilityZone: this.availabilityZone,
101
- InstanceOSUser: userName,
102
- SSHPublicKey: publicKeyString,
103
- };
104
- const rval = await this.ec2InstanceConnect.send(new SendSSHPublicKeyCommand(req));
105
- return rval;
106
- }
107
- }
@@ -1,31 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import os from 'os';
4
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
5
- import { Ec2Ratchet } from './ec2-ratchet.js';
6
- describe('#EC2Ratchet', function () {
7
- xit('should send a public key', async () => {
8
- const ratchet = new Ec2Ratchet();
9
- const instId = 'i-replace_me';
10
- const pubKey = fs.readFileSync(path.join(os.homedir(), '.ssh/id_rsa.pub')).toString();
11
- const res = await ratchet.sendPublicKeyToEc2Instance(instId, pubKey);
12
- Logger.info('Got : %j', res);
13
- expect(res).toBeTruthy();
14
- });
15
- xit('should list instances', async () => {
16
- const ratchet = new Ec2Ratchet();
17
- const res = await ratchet.listAllInstances();
18
- Logger.info('Got : %j', res);
19
- expect(res).toBeTruthy();
20
- expect(res.length).toBeGreaterThan(1);
21
- });
22
- xit('should start and stop an instance', async () => {
23
- const ratchet = new Ec2Ratchet();
24
- const instId = 'i-replace_me';
25
- Logger.info('First start');
26
- await ratchet.launchInstance(instId, 1000 * 60);
27
- Logger.info('Next stop');
28
- await ratchet.stopInstance(instId, 1000 * 60);
29
- Logger.info('Complete');
30
- });
31
- });
@@ -1,24 +0,0 @@
1
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
2
- import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
3
- export class CascadeEnvironmentServiceProvider {
4
- providers;
5
- constructor(providers) {
6
- this.providers = providers;
7
- RequireRatchet.notNullOrUndefined(providers);
8
- RequireRatchet.true(providers.length > 0);
9
- }
10
- async fetchConfig(name) {
11
- Logger.silly('CascadeEnvironmentServiceProvider fetch for %s', name);
12
- let rval = null;
13
- for (let i = 0; i < this.providers.length && !rval; i++) {
14
- try {
15
- rval = await this.providers[i].fetchConfig(name);
16
- }
17
- catch (err) {
18
- Logger.error('Provider %d failed - trying next : %s', i, err, err);
19
- rval = null;
20
- }
21
- }
22
- return rval;
23
- }
24
- }
@@ -1,30 +0,0 @@
1
- import { ErrorRatchet } from '@bitblit/ratchet-common/lib/lang/error-ratchet.js';
2
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
3
- import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
4
- import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
5
- export class EnvVarEnvironmentServiceProvider {
6
- envVarName;
7
- constructor(envVarName) {
8
- this.envVarName = envVarName;
9
- RequireRatchet.notNullOrUndefined(envVarName);
10
- }
11
- async fetchConfig() {
12
- Logger.silly('EnvVarEnvironmentServiceProvider fetch for %s', this.envVarName);
13
- let rval = null;
14
- const src = process ? process.env : global ? global : {};
15
- const toParse = StringRatchet.trimToNull(src[this.envVarName]);
16
- if (toParse) {
17
- try {
18
- rval = JSON.parse(toParse);
19
- }
20
- catch (err) {
21
- Logger.error('Failed to read env - null or invalid JSON : %s : %s', err, toParse, err);
22
- throw err;
23
- }
24
- }
25
- else {
26
- ErrorRatchet.throwFormattedErr('Could not find env var with name : %s', this.envVarName);
27
- }
28
- return rval;
29
- }
30
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,50 +0,0 @@
1
- import { ErrorRatchet } from '@bitblit/ratchet-common/lib/lang/error-ratchet.js';
2
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
3
- import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
4
- import { PromiseRatchet } from '@bitblit/ratchet-common/lib/lang/promise-ratchet.js';
5
- export class EnvironmentService {
6
- provider;
7
- cfg;
8
- readPromiseCache = new Map();
9
- static defaultEnvironmentServiceConfig() {
10
- const rval = {
11
- maxRetries: 3,
12
- backoffMultiplierMS: 500,
13
- };
14
- return rval;
15
- }
16
- constructor(provider, cfg = EnvironmentService.defaultEnvironmentServiceConfig()) {
17
- this.provider = provider;
18
- this.cfg = cfg;
19
- RequireRatchet.notNullOrUndefined(provider);
20
- RequireRatchet.notNullOrUndefined(cfg);
21
- }
22
- async getConfig(name) {
23
- Logger.silly('EnvService:Request to read config %s', name);
24
- if (!this.readPromiseCache.has(name)) {
25
- Logger.silly('EnvService: Nothing in cache - adding');
26
- this.readPromiseCache.set(name, this.getConfigUncached(name));
27
- }
28
- return this.readPromiseCache.get(name);
29
- }
30
- async getConfigUncached(name) {
31
- let tryCount = 1;
32
- let rval = null;
33
- while (!rval && tryCount < this.cfg.maxRetries) {
34
- tryCount++;
35
- Logger.silly('Attempting fetch of %s', name);
36
- try {
37
- rval = await this.provider.fetchConfig(name);
38
- }
39
- catch (err) {
40
- const waitMS = tryCount * this.cfg.backoffMultiplierMS;
41
- Logger.info('Error attempting to fetch config %s (try %d of %d, waiting %s MS): %s', name, tryCount, this.cfg.maxRetries, waitMS, err, err);
42
- await PromiseRatchet.wait(waitMS);
43
- }
44
- }
45
- if (!rval) {
46
- ErrorRatchet.throwFormattedErr('Was unable to fetch config %s even after %d retries', name, this.cfg.maxRetries);
47
- }
48
- return rval;
49
- }
50
- }
@@ -1,22 +0,0 @@
1
- import { EnvironmentService } from './environment-service.js';
2
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
3
- import { FixedEnvironmentServiceProvider } from './fixed-environment-service-provider.js';
4
- const fixed = FixedEnvironmentServiceProvider.fromRecord({ a: 'b', c: 5 });
5
- describe('#environmentService', function () {
6
- it('should throw exception on missing environment values', async () => {
7
- try {
8
- const es = new EnvironmentService(fixed);
9
- const vals = await es.getConfig('i_do_not_exist');
10
- this.bail('Should not have returned a value');
11
- }
12
- catch (err) {
13
- expect(err).toBeTruthy();
14
- Logger.info('Success - threw %s', err);
15
- }
16
- });
17
- it('should find a valid value', async () => {
18
- const es = new EnvironmentService(fixed);
19
- const vals = await es.getConfig('c');
20
- expect(vals).toBeTruthy();
21
- });
22
- });
@@ -1,21 +0,0 @@
1
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
2
- import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
3
- export class FixedEnvironmentServiceProvider {
4
- value;
5
- constructor(value) {
6
- this.value = value;
7
- RequireRatchet.notNullOrUndefined(value);
8
- }
9
- static fromRecord(record) {
10
- const m = new Map();
11
- Object.keys(record).forEach((k) => {
12
- m.set(k, record[k]);
13
- });
14
- return new FixedEnvironmentServiceProvider(m);
15
- }
16
- async fetchConfig(name) {
17
- Logger.silly('FixedEnvironmentServiceProvider fetch for %s', name);
18
- const rval = this.value.get(name);
19
- return rval;
20
- }
21
- }
@@ -1,27 +0,0 @@
1
- import { S3CacheRatchet } from '../s3/s3-cache-ratchet.js';
2
- import { RequireRatchet } from '@bitblit/ratchet-common/lib/lang/require-ratchet.js';
3
- import { Logger } from '@bitblit/ratchet-common/lib/logger/logger.js';
4
- import { StringRatchet } from '@bitblit/ratchet-common/lib/lang/string-ratchet.js';
5
- import { StopWatch } from '@bitblit/ratchet-common/lib/lang/stop-watch.js';
6
- import { S3Client } from '@aws-sdk/client-s3';
7
- export class S3EnvironmentServiceProvider {
8
- cfg;
9
- ratchet;
10
- constructor(cfg) {
11
- this.cfg = cfg;
12
- RequireRatchet.notNullOrUndefined(cfg);
13
- RequireRatchet.notNullOrUndefined(cfg.bucketName);
14
- RequireRatchet.notNullOrUndefined(cfg.region);
15
- RequireRatchet.true(!!cfg.s3Override || !!cfg.region, 'You must set either region or S3Override');
16
- const s3 = cfg.s3Override || new S3Client({ region: cfg.region });
17
- this.ratchet = new S3CacheRatchet(s3, cfg.bucketName);
18
- }
19
- async fetchConfig(name) {
20
- const readPath = StringRatchet.trimToEmpty(this.cfg.pathPrefix) + name + StringRatchet.trimToEmpty(this.cfg.pathSuffix);
21
- Logger.silly('S3EnvironmentServiceProvider:Request to read config from : %s / %s', this.cfg.bucketName, readPath);
22
- const sw = new StopWatch();
23
- const rval = await this.ratchet.fetchCacheFileAsObject(readPath);
24
- sw.log();
25
- return rval;
26
- }
27
- }