@kapeta/local-cluster-service 0.40.0 → 0.40.2

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.
@@ -8,9 +8,10 @@ jobs:
8
8
  build:
9
9
  runs-on: ubuntu-latest
10
10
  steps:
11
- - uses: actions/checkout@v3
11
+ - uses: actions/checkout@v4
12
12
  with:
13
13
  token: ${{ secrets.BOT_TOKEN }}
14
+ fetch-depth: 0
14
15
  - uses: actions/setup-node@v3
15
16
  - run: npm ci
16
17
  - run: npm run build --if-present
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [0.40.2](https://github.com/kapetacom/local-cluster-service/compare/v0.40.1...v0.40.2) (2024-03-11)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Several issues when running external docker images ([#132](https://github.com/kapetacom/local-cluster-service/issues/132)) ([5218368](https://github.com/kapetacom/local-cluster-service/commit/521836819aa39084fe1c4f781fb560682e42fc8f))
7
+
8
+ ## [0.40.1](https://github.com/kapetacom/local-cluster-service/compare/v0.40.0...v0.40.1) (2024-02-28)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * bump release ([1a6fbb2](https://github.com/kapetacom/local-cluster-service/commit/1a6fbb2d8095e1bc7878e35e52fe40a5a498f9e6))
14
+
1
15
  # [0.40.0](https://github.com/kapetacom/local-cluster-service/compare/v0.39.2...v0.40.0) (2024-02-28)
2
16
 
3
17
 
@@ -216,6 +216,10 @@ class ContainerManager {
216
216
  if (!tag) {
217
217
  tag = 'latest';
218
218
  }
219
+ if (tag === 'local') {
220
+ // Local image - no need to pull
221
+ return false;
222
+ }
219
223
  const imageTagList = (await this.docker().listImages({}))
220
224
  .filter((imageData) => !!imageData.RepoTags)
221
225
  .map((imageData) => imageData.RepoTags);
@@ -619,16 +623,22 @@ class ContainerManager {
619
623
  buildDockerImage(dockerFile, imageName) {
620
624
  const taskName = `Building docker image: ${imageName}`;
621
625
  const processor = async (task) => {
622
- const timeStarted = Date.now();
623
- const stream = await this.docker().buildImage({
626
+ const baseDir = path_1.default.dirname(dockerFile);
627
+ const entries = await fs_extra_1.default.readdir(baseDir);
628
+ const contextInfo = {
624
629
  context: path_1.default.dirname(dockerFile),
625
- src: [path_1.default.basename(dockerFile)],
626
- }, {
630
+ src: entries,
631
+ };
632
+ const stream = await this.docker().buildImage(contextInfo, {
627
633
  t: imageName,
628
634
  dockerfile: path_1.default.basename(dockerFile),
629
635
  });
630
636
  await processJsonStream(`image:build:${imageName}`, stream, (data) => {
631
- if (data.stream) {
637
+ if (data.error) {
638
+ task.future.reject(new Error(data.error));
639
+ task.addLog(data.error, 'ERROR');
640
+ }
641
+ else if (data.stream) {
632
642
  // Emit raw output to the task log
633
643
  task.addLog(data.stream);
634
644
  }
@@ -15,6 +15,7 @@ const pathTemplateParser_1 = require("../../utils/pathTemplateParser");
15
15
  const networkManager_1 = require("../../networkManager");
16
16
  const socketManager_1 = require("../../socketManager");
17
17
  const qs_1 = require("qs");
18
+ const web_1 = require("./web");
18
19
  function getRestMethodId(restResource, httpMethod, httpPath) {
19
20
  return lodash_1.default.findKey(restResource.spec.methods, (method) => {
20
21
  let methodType = method.method ? method.method.toUpperCase() : 'GET';
@@ -63,6 +64,10 @@ function resolveMethods(req, opts) {
63
64
  };
64
65
  }
65
66
  function proxyRestRequest(req, res, opts) {
67
+ if (lodash_1.default.isEmpty(opts.consumerResource.spec.methods) && lodash_1.default.isEmpty(opts.providerResource.spec.methods)) {
68
+ // If there are no methods defined, we assume the user controls the path and we just proxy the raw request
69
+ return (0, web_1.proxyHttpRequest)(req, res, opts);
70
+ }
66
71
  let { consumerMethod, providerMethod } = resolveMethods(req, opts);
67
72
  const consumerPathTemplate = (0, pathTemplateParser_1.pathTemplateParser)(consumerMethod.path);
68
73
  const providerPathTemplate = (0, pathTemplateParser_1.pathTemplateParser)(providerMethod.path);
@@ -20,8 +20,8 @@ function proxyHttpRequest(req, res, opts) {
20
20
  delete requestHeaders['connection'];
21
21
  delete requestHeaders['host'];
22
22
  delete requestHeaders['origin'];
23
- const sourceBasePath = opts.consumerResource.spec.path;
24
- const targetBasePath = opts.providerResource.spec.path;
23
+ const sourceBasePath = opts.consumerResource.spec.path ?? '/';
24
+ const targetBasePath = opts.providerResource.spec.path ?? '/';
25
25
  let path = opts.consumerPath;
26
26
  if (opts.consumerPath.startsWith(sourceBasePath)) {
27
27
  path = path.replace(sourceBasePath, targetBasePath);
@@ -34,7 +34,7 @@ const DOCKER_ENV_VARS = [
34
34
  `KAPETA_LOCAL_SERVER=0.0.0.0`,
35
35
  `KAPETA_LOCAL_CLUSTER_HOST=${types_1.DOCKER_HOST_INTERNAL}`,
36
36
  `KAPETA_ENVIRONMENT_TYPE=docker`,
37
- `KAPETA_ENVIRONMENT_PLATFORM=${node_os_1.default.platform()}`
37
+ `KAPETA_ENVIRONMENT_PLATFORM=${node_os_1.default.platform()}`,
38
38
  ];
39
39
  async function getProvider(uri) {
40
40
  const providers = await definitionsManager_1.definitionsManager.getProviderDefinitions();
@@ -172,8 +172,15 @@ class BlockInstanceRunner {
172
172
  if (!fs_extra_1.default.existsSync(dockerFile)) {
173
173
  throw new Error(`Dockerfile not found at: ${dockerFile}`);
174
174
  }
175
- const task = containerManager_1.containerManager.buildDockerImage(dockerFile, blockInfo.fullName + ':local');
176
- await task.wait();
175
+ console.log('Building docker image from Dockerfile "%s": %s ', dockerFile, dockerImage);
176
+ try {
177
+ const task = containerManager_1.containerManager.buildDockerImage(dockerFile, dockerImage);
178
+ await task.wait();
179
+ }
180
+ catch (err) {
181
+ throw new Error(`Error building docker image: ${err}`);
182
+ }
183
+ console.log('Docker images was build from file "%s": %s', dockerFile, dockerImage);
177
184
  }
178
185
  const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, targetKindUri.id);
179
186
  const startCmd = localContainer.handlers?.onCreate ? localContainer.handlers.onCreate : '';
@@ -205,7 +212,7 @@ class BlockInstanceRunner {
205
212
  ...dockerOpts,
206
213
  Image: dockerImage,
207
214
  name: containerName,
208
- WorkingDir: workingDir,
215
+ WorkingDir: isDockerImage ? workingDir : undefined,
209
216
  Labels: {
210
217
  ...customLabels,
211
218
  instance: blockInstance.id,
@@ -41,8 +41,8 @@ class InternalConfigProvider {
41
41
  getInstanceId() {
42
42
  return this.instanceId;
43
43
  }
44
- getServerPort(portType) {
45
- return serviceManager_1.serviceManager.ensureServicePort(this.systemId, this.instanceId, portType);
44
+ async getServerPort(portType) {
45
+ return '80';
46
46
  }
47
47
  async getServiceAddress(serviceName, portType) {
48
48
  return serviceManager_1.serviceManager.getConsumerAddress(this.systemId, this.instanceId, serviceName, portType, this.environment);
@@ -216,6 +216,10 @@ class ContainerManager {
216
216
  if (!tag) {
217
217
  tag = 'latest';
218
218
  }
219
+ if (tag === 'local') {
220
+ // Local image - no need to pull
221
+ return false;
222
+ }
219
223
  const imageTagList = (await this.docker().listImages({}))
220
224
  .filter((imageData) => !!imageData.RepoTags)
221
225
  .map((imageData) => imageData.RepoTags);
@@ -619,16 +623,22 @@ class ContainerManager {
619
623
  buildDockerImage(dockerFile, imageName) {
620
624
  const taskName = `Building docker image: ${imageName}`;
621
625
  const processor = async (task) => {
622
- const timeStarted = Date.now();
623
- const stream = await this.docker().buildImage({
626
+ const baseDir = path_1.default.dirname(dockerFile);
627
+ const entries = await fs_extra_1.default.readdir(baseDir);
628
+ const contextInfo = {
624
629
  context: path_1.default.dirname(dockerFile),
625
- src: [path_1.default.basename(dockerFile)],
626
- }, {
630
+ src: entries,
631
+ };
632
+ const stream = await this.docker().buildImage(contextInfo, {
627
633
  t: imageName,
628
634
  dockerfile: path_1.default.basename(dockerFile),
629
635
  });
630
636
  await processJsonStream(`image:build:${imageName}`, stream, (data) => {
631
- if (data.stream) {
637
+ if (data.error) {
638
+ task.future.reject(new Error(data.error));
639
+ task.addLog(data.error, 'ERROR');
640
+ }
641
+ else if (data.stream) {
632
642
  // Emit raw output to the task log
633
643
  task.addLog(data.stream);
634
644
  }
@@ -15,6 +15,7 @@ const pathTemplateParser_1 = require("../../utils/pathTemplateParser");
15
15
  const networkManager_1 = require("../../networkManager");
16
16
  const socketManager_1 = require("../../socketManager");
17
17
  const qs_1 = require("qs");
18
+ const web_1 = require("./web");
18
19
  function getRestMethodId(restResource, httpMethod, httpPath) {
19
20
  return lodash_1.default.findKey(restResource.spec.methods, (method) => {
20
21
  let methodType = method.method ? method.method.toUpperCase() : 'GET';
@@ -63,6 +64,10 @@ function resolveMethods(req, opts) {
63
64
  };
64
65
  }
65
66
  function proxyRestRequest(req, res, opts) {
67
+ if (lodash_1.default.isEmpty(opts.consumerResource.spec.methods) && lodash_1.default.isEmpty(opts.providerResource.spec.methods)) {
68
+ // If there are no methods defined, we assume the user controls the path and we just proxy the raw request
69
+ return (0, web_1.proxyHttpRequest)(req, res, opts);
70
+ }
66
71
  let { consumerMethod, providerMethod } = resolveMethods(req, opts);
67
72
  const consumerPathTemplate = (0, pathTemplateParser_1.pathTemplateParser)(consumerMethod.path);
68
73
  const providerPathTemplate = (0, pathTemplateParser_1.pathTemplateParser)(providerMethod.path);
@@ -20,8 +20,8 @@ function proxyHttpRequest(req, res, opts) {
20
20
  delete requestHeaders['connection'];
21
21
  delete requestHeaders['host'];
22
22
  delete requestHeaders['origin'];
23
- const sourceBasePath = opts.consumerResource.spec.path;
24
- const targetBasePath = opts.providerResource.spec.path;
23
+ const sourceBasePath = opts.consumerResource.spec.path ?? '/';
24
+ const targetBasePath = opts.providerResource.spec.path ?? '/';
25
25
  let path = opts.consumerPath;
26
26
  if (opts.consumerPath.startsWith(sourceBasePath)) {
27
27
  path = path.replace(sourceBasePath, targetBasePath);
@@ -34,7 +34,7 @@ const DOCKER_ENV_VARS = [
34
34
  `KAPETA_LOCAL_SERVER=0.0.0.0`,
35
35
  `KAPETA_LOCAL_CLUSTER_HOST=${types_1.DOCKER_HOST_INTERNAL}`,
36
36
  `KAPETA_ENVIRONMENT_TYPE=docker`,
37
- `KAPETA_ENVIRONMENT_PLATFORM=${node_os_1.default.platform()}`
37
+ `KAPETA_ENVIRONMENT_PLATFORM=${node_os_1.default.platform()}`,
38
38
  ];
39
39
  async function getProvider(uri) {
40
40
  const providers = await definitionsManager_1.definitionsManager.getProviderDefinitions();
@@ -172,8 +172,15 @@ class BlockInstanceRunner {
172
172
  if (!fs_extra_1.default.existsSync(dockerFile)) {
173
173
  throw new Error(`Dockerfile not found at: ${dockerFile}`);
174
174
  }
175
- const task = containerManager_1.containerManager.buildDockerImage(dockerFile, blockInfo.fullName + ':local');
176
- await task.wait();
175
+ console.log('Building docker image from Dockerfile "%s": %s ', dockerFile, dockerImage);
176
+ try {
177
+ const task = containerManager_1.containerManager.buildDockerImage(dockerFile, dockerImage);
178
+ await task.wait();
179
+ }
180
+ catch (err) {
181
+ throw new Error(`Error building docker image: ${err}`);
182
+ }
183
+ console.log('Docker images was build from file "%s": %s', dockerFile, dockerImage);
177
184
  }
178
185
  const containerName = await (0, utils_1.getBlockInstanceContainerName)(this._systemId, blockInstance.id, targetKindUri.id);
179
186
  const startCmd = localContainer.handlers?.onCreate ? localContainer.handlers.onCreate : '';
@@ -205,7 +212,7 @@ class BlockInstanceRunner {
205
212
  ...dockerOpts,
206
213
  Image: dockerImage,
207
214
  name: containerName,
208
- WorkingDir: workingDir,
215
+ WorkingDir: isDockerImage ? workingDir : undefined,
209
216
  Labels: {
210
217
  ...customLabels,
211
218
  instance: blockInstance.id,
@@ -41,8 +41,8 @@ class InternalConfigProvider {
41
41
  getInstanceId() {
42
42
  return this.instanceId;
43
43
  }
44
- getServerPort(portType) {
45
- return serviceManager_1.serviceManager.ensureServicePort(this.systemId, this.instanceId, portType);
44
+ async getServerPort(portType) {
45
+ return '80';
46
46
  }
47
47
  async getServiceAddress(serviceName, portType) {
48
48
  return serviceManager_1.serviceManager.getConsumerAddress(this.systemId, this.instanceId, serviceName, portType, this.environment);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.40.0",
3
+ "version": "0.40.2",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -306,6 +306,11 @@ class ContainerManager {
306
306
  tag = 'latest';
307
307
  }
308
308
 
309
+ if (tag === 'local') {
310
+ // Local image - no need to pull
311
+ return false;
312
+ }
313
+
309
314
  const imageTagList = (await this.docker().listImages({}))
310
315
  .filter((imageData) => !!imageData.RepoTags)
311
316
  .map((imageData) => imageData.RepoTags as string[]);
@@ -786,20 +791,23 @@ class ContainerManager {
786
791
  buildDockerImage(dockerFile: string, imageName: string) {
787
792
  const taskName = `Building docker image: ${imageName}`;
788
793
  const processor = async (task: Task) => {
789
- const timeStarted = Date.now();
790
- const stream = await this.docker().buildImage(
791
- {
792
- context: Path.dirname(dockerFile),
793
- src: [Path.basename(dockerFile)],
794
- },
795
- {
796
- t: imageName,
797
- dockerfile: Path.basename(dockerFile),
798
- }
799
- );
794
+ const baseDir = Path.dirname(dockerFile);
795
+ const entries = await FSExtra.readdir(baseDir);
796
+ const contextInfo = {
797
+ context: Path.dirname(dockerFile),
798
+ src: entries,
799
+ };
800
+
801
+ const stream = await this.docker().buildImage(contextInfo, {
802
+ t: imageName,
803
+ dockerfile: Path.basename(dockerFile),
804
+ });
800
805
 
801
806
  await processJsonStream<string>(`image:build:${imageName}`, stream, (data) => {
802
- if (data.stream) {
807
+ if (data.error) {
808
+ task.future.reject(new Error(data.error));
809
+ task.addLog(data.error, 'ERROR');
810
+ } else if (data.stream) {
803
811
  // Emit raw output to the task log
804
812
  task.addLog(data.stream);
805
813
  }
@@ -15,6 +15,7 @@ import { ProxyRequestInfo, SimpleRequest, StringMap } from '../../types';
15
15
  import { StringBodyRequest } from '../../middleware/stringBody';
16
16
  import { Resource } from '@kapeta/schemas';
17
17
  import { stringify } from 'qs';
18
+ import { proxyHttpRequest } from './web';
18
19
 
19
20
  export function getRestMethodId(restResource: Resource, httpMethod: string, httpPath: string) {
20
21
  return _.findKey(restResource.spec.methods, (method) => {
@@ -86,6 +87,10 @@ function resolveMethods(req: Request, opts: ProxyRequestInfo) {
86
87
  }
87
88
 
88
89
  export function proxyRestRequest(req: StringBodyRequest, res: Response, opts: ProxyRequestInfo) {
90
+ if (_.isEmpty(opts.consumerResource.spec.methods) && _.isEmpty(opts.providerResource.spec.methods)) {
91
+ // If there are no methods defined, we assume the user controls the path and we just proxy the raw request
92
+ return proxyHttpRequest(req, res, opts);
93
+ }
89
94
  let { consumerMethod, providerMethod } = resolveMethods(req, opts);
90
95
 
91
96
  const consumerPathTemplate = pathTemplateParser(consumerMethod.path);
@@ -21,8 +21,8 @@ export function proxyHttpRequest(req: StringBodyRequest, res: Response, opts: Pr
21
21
  delete requestHeaders['host'];
22
22
  delete requestHeaders['origin'];
23
23
 
24
- const sourceBasePath = opts.consumerResource.spec.path;
25
- const targetBasePath = opts.providerResource.spec.path;
24
+ const sourceBasePath = opts.consumerResource.spec.path ?? '/';
25
+ const targetBasePath = opts.providerResource.spec.path ?? '/';
26
26
  let path = opts.consumerPath;
27
27
  if (opts.consumerPath.startsWith(sourceBasePath)) {
28
28
  path = path.replace(sourceBasePath, targetBasePath);
@@ -48,7 +48,7 @@ const DOCKER_ENV_VARS = [
48
48
  `KAPETA_LOCAL_SERVER=0.0.0.0`,
49
49
  `KAPETA_LOCAL_CLUSTER_HOST=${DOCKER_HOST_INTERNAL}`,
50
50
  `KAPETA_ENVIRONMENT_TYPE=docker`,
51
- `KAPETA_ENVIRONMENT_PLATFORM=${OS.platform()}`
51
+ `KAPETA_ENVIRONMENT_PLATFORM=${OS.platform()}`,
52
52
  ];
53
53
 
54
54
  async function getProvider(uri: KapetaURI) {
@@ -231,8 +231,16 @@ export class BlockInstanceRunner {
231
231
  if (!FSExtra.existsSync(dockerFile)) {
232
232
  throw new Error(`Dockerfile not found at: ${dockerFile}`);
233
233
  }
234
- const task = containerManager.buildDockerImage(dockerFile, blockInfo.fullName + ':local');
235
- await task.wait();
234
+
235
+ console.log('Building docker image from Dockerfile "%s": %s ', dockerFile, dockerImage);
236
+ try {
237
+ const task = containerManager.buildDockerImage(dockerFile, dockerImage);
238
+ await task.wait();
239
+ } catch (err: any) {
240
+ throw new Error(`Error building docker image: ${err}`);
241
+ }
242
+
243
+ console.log('Docker images was build from file "%s": %s', dockerFile, dockerImage);
236
244
  }
237
245
 
238
246
  const containerName = await getBlockInstanceContainerName(this._systemId, blockInstance.id, targetKindUri.id);
@@ -275,7 +283,7 @@ export class BlockInstanceRunner {
275
283
  ...dockerOpts,
276
284
  Image: dockerImage,
277
285
  name: containerName,
278
- WorkingDir: workingDir,
286
+ WorkingDir: isDockerImage ? workingDir : undefined,
279
287
  Labels: {
280
288
  ...customLabels,
281
289
  instance: blockInstance.id,
@@ -59,8 +59,8 @@ export class InternalConfigProvider implements ConfigProvider {
59
59
  getInstanceId(): string {
60
60
  return this.instanceId;
61
61
  }
62
- getServerPort(portType?: string | undefined): Promise<string> {
63
- return serviceManager.ensureServicePort(this.systemId, this.instanceId, portType);
62
+ async getServerPort(portType?: string | undefined): Promise<string> {
63
+ return '80';
64
64
  }
65
65
  async getServiceAddress(serviceName: string, portType: string): Promise<string | null> {
66
66
  return serviceManager.getConsumerAddress(