@flowfuse/driver-kubernetes 2.21.1 → 2.21.2-057ae7d-202509080755.0

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.
@@ -9,7 +9,7 @@ jobs:
9
9
  runs-on: ubuntu-latest
10
10
  steps:
11
11
  - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
12
- - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
12
+ - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
13
13
  with:
14
14
  node-version: 18
15
15
  - run: npm ci
package/kubernetes.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const got = require('got')
2
2
  const FormData = require('form-data')
3
- const k8s = require('@kubernetes/client-node')
3
+ // const k8s = require('@kubernetes/client-node')
4
4
  const _ = require('lodash')
5
5
  const awsEFS = require('./lib/aws-efs.js')
6
6
  const { WebSocket } = require('ws')
@@ -15,6 +15,8 @@ const {
15
15
  mqttSchemaAgentServiceTemplate
16
16
  } = require('./templates.js')
17
17
 
18
+ let k8s
19
+
18
20
  /**
19
21
  * Kubernates Container driver
20
22
  *
@@ -350,13 +352,14 @@ const createProject = async (project, options) => {
350
352
  const localPVC = await createPersistentVolumeClaim(project, options)
351
353
  // console.log(JSON.stringify(localPVC, null, 2))
352
354
  try {
353
- await this._k8sApi.createNamespacedPersistentVolumeClaim(namespace, localPVC)
355
+ await this._k8sApi.createNamespacedPersistentVolumeClaim({ namespace, body: localPVC })
354
356
  } catch (err) {
355
- if (err.statusCode === 409) {
357
+ console.log(JSON.stringify(err))
358
+ if (err.code === 409) {
356
359
  this._app.log.warn(`[k8s] PVC for instance ${project.id} already exists, proceeding...`)
357
360
  } else {
358
361
  if (project.state !== 'suspended') {
359
- this._app.log.error(`[k8s] Instance ${project.id} - error creating PVC: ${err.toString()} ${err.statusCode}`)
362
+ this._app.log.error(`[k8s] Instance ${project.id} - error creating PVC: ${err.toString()} ${err.code} ${err.stack}`)
360
363
  // console.log(err)
361
364
  throw err
362
365
  }
@@ -365,18 +368,18 @@ const createProject = async (project, options) => {
365
368
  }
366
369
 
367
370
  try {
368
- await this._k8sAppApi.createNamespacedDeployment(namespace, localDeployment)
371
+ await this._k8sAppApi.createNamespacedDeployment({ namespace, body: localDeployment })
369
372
  } catch (err) {
370
- if (err.statusCode === 409) {
373
+ if (err.code === 409) {
371
374
  // If deployment exists, perform an upgrade
372
375
  this._app.log.warn(`[k8s] Deployment for instance ${project.id} already exists. Upgrading deployment`)
373
- const result = await this._k8sAppApi.readNamespacedDeployment(project.safeName, namespace)
376
+ const result = await this._k8sAppApi.readNamespacedDeployment({ name: project.safeName, namespace })
374
377
 
375
- const existingDeployment = result.body
378
+ const existingDeployment = result
376
379
  // Check if the metadata and spec are aligned. They won't be though (at minimal because we regenerate auth)
377
380
  if (!_.isEqual(existingDeployment.metadata, localDeployment.metadata) || !_.isEqual(existingDeployment.spec, localDeployment.spec)) {
378
381
  // If not aligned, replace the deployment
379
- await this._k8sAppApi.replaceNamespacedDeployment(project.safeName, namespace, localDeployment)
382
+ await this._k8sAppApi.replaceNamespacedDeployment({ name: project.safeName, namespace, body: localDeployment })
380
383
  }
381
384
  } else {
382
385
  // Log other errors and rethrow them for additional higher-level handling
@@ -392,7 +395,7 @@ const createProject = async (project, options) => {
392
395
  let counter = 0
393
396
  const pollInterval = setInterval(async () => {
394
397
  try {
395
- await this._k8sAppApi.readNamespacedDeployment(project.safeName, this._namespace)
398
+ await this._k8sAppApi.readNamespacedDeployment({ name: project.safeName, namespace: this._namespace })
396
399
  clearInterval(pollInterval)
397
400
  resolve()
398
401
  } catch (err) {
@@ -408,9 +411,9 @@ const createProject = async (project, options) => {
408
411
  })
409
412
 
410
413
  try {
411
- await this._k8sApi.createNamespacedService(namespace, localService)
414
+ await this._k8sApi.createNamespacedService({ namespace, body: localService })
412
415
  } catch (err) {
413
- if (err.statusCode === 409) {
416
+ if (err.code === 409) {
414
417
  this._app.log.warn(`[k8s] Service for instance ${project.id} already exists, proceeding...`)
415
418
  } else {
416
419
  if (project.state !== 'suspended') {
@@ -425,7 +428,7 @@ const createProject = async (project, options) => {
425
428
  let counter = 0
426
429
  const pollInterval = setInterval(async () => {
427
430
  try {
428
- await this._k8sApi.readNamespacedService(prefix + project.safeName, this._namespace)
431
+ await this._k8sApi.readNamespacedService({ name: prefix + project.safeName, namespace: this._namespace })
429
432
  clearInterval(pollInterval)
430
433
  resolve()
431
434
  } catch (err) {
@@ -440,13 +443,13 @@ const createProject = async (project, options) => {
440
443
  })
441
444
 
442
445
  try {
443
- await this._k8sNetApi.createNamespacedIngress(namespace, localIngress)
446
+ await this._k8sNetApi.createNamespacedIngress({ namespace, body: localIngress })
444
447
  } catch (err) {
445
- if (err.statusCode === 409) {
448
+ if (err.code === 409) {
446
449
  this._app.log.warn(`[k8s] Ingress for instance ${project.id} already exists, proceeding...`)
447
450
  } else {
448
451
  if (project.state !== 'suspended') {
449
- this._app.log.error(`[k8s] Instance ${project.id} - error creating ingress: ${err.toString()}`)
452
+ this._app.log.error(`[k8s] Instance ${project.id} - error creating ingress: ${err.toString()} ${err.stack}}`)
450
453
  throw err
451
454
  }
452
455
  }
@@ -456,13 +459,13 @@ const createProject = async (project, options) => {
456
459
  if (customHostname) {
457
460
  const customHostnameIngress = await createCustomIngress(project, customHostname, options)
458
461
  try {
459
- await this._k8sNetApi.createNamespacedIngress(namespace, customHostnameIngress)
462
+ await this._k8sNetApi.createNamespacedIngress({ namespace, body: customHostnameIngress })
460
463
  } catch (err) {
461
- if (err.statusCode === 409) {
464
+ if (err.code === 409) {
462
465
  this._app.log.warn(`[k8s] Custom Hostname Ingress for instance ${project.id} already exists, proceeding...`)
463
466
  } else {
464
467
  if (project.state !== 'suspended') {
465
- this._app.log.error(`[k8s] Instance ${project.id} - error creating custom hostname ingress: ${err.toString()}`)
468
+ this._app.log.error(`[k8s] Instance ${project.id} - error creating custom hostname ingress: ${err.toString()} ${err.stack}`)
466
469
  throw err
467
470
  }
468
471
  }
@@ -474,7 +477,7 @@ const createProject = async (project, options) => {
474
477
  let counter = 0
475
478
  const pollInterval = setInterval(async () => {
476
479
  try {
477
- await this._k8sNetApi.readNamespacedIngress(project.safeName, this._namespace)
480
+ await this._k8sNetApi.readNamespacedIngress({ name: project.safeName, namespace: this._namespace })
478
481
  clearInterval(pollInterval)
479
482
  resolve()
480
483
  } catch (err) {
@@ -500,8 +503,8 @@ const createProject = async (project, options) => {
500
503
  const getEndpoints = async (project) => {
501
504
  const prefix = project.safeName.match(/^[0-9]/) ? 'srv-' : ''
502
505
  if (await project.getSetting('ha')) {
503
- const endpoints = await this._k8sApi.readNamespacedEndpoints(`${prefix}${project.safeName}`, this._namespace)
504
- const addresses = endpoints.body.subsets[0].addresses.map(a => { return a.ip })
506
+ const endpoints = await this._k8sApi.readNamespacedEndpoints({ name: `${prefix}${project.safeName}`, namespace: this._namespace })
507
+ const addresses = endpoints.subsets[0].addresses.map(a => { return a.ip })
505
508
  const hosts = []
506
509
  for (const address in addresses) {
507
510
  hosts.push(addresses[address])
@@ -553,11 +556,11 @@ const createMQTTTopicAgent = async (broker) => {
553
556
  // console.log(JSON.stringify(localPod,null,2))
554
557
  // console.log(JSON.stringify(localService,null,2))
555
558
  try {
556
- await this._k8sApi.createNamespacedPod(namespace, localPod)
557
- await this._k8sApi.createNamespacedService(namespace, localService)
559
+ console.log(namespace, localPod.metadata.name)
560
+ await this._k8sApi.createNamespacedPod({ namespace, body: localPod })
561
+ await this._k8sApi.createNamespacedService({ namespace, body: localService })
558
562
  } catch (err) {
559
- this._app.log.error(`[k8s] Problem creating MQTT Agent ${broker.hashid} - ${err.toString()}`)
560
- console.log(err)
563
+ this._app.log.error(`[k8s] Problem creating MQTT Agent ${broker.hashid} in ${namespace} - ${err.toString()} ${err.stack}`)
561
564
  }
562
565
  }
563
566
 
@@ -569,6 +572,11 @@ module.exports = {
569
572
  * @return {forge.containers.ProjectArguments}
570
573
  */
571
574
  init: async (app, options) => {
575
+ try {
576
+ k8s = await import('@kubernetes/client-node')
577
+ } catch (err) {
578
+ throw Error('Failed to load Kubernetes node client', { cause: err })
579
+ }
572
580
  this._app = app
573
581
  this._projects = {}
574
582
  this._options = options
@@ -657,8 +665,8 @@ module.exports = {
657
665
  const currentType = await project.getSetting('k8sType')
658
666
  if (currentType === 'deployment') {
659
667
  try {
660
- this._app.log.info(`[k8s] Testing ${project.id} in ${namespace} deployment exists`)
661
- await this._k8sAppApi.readNamespacedDeployment(project.safeName, namespace)
668
+ this._app.log.info(`[k8s] Testing ${project.id} (${project.safeName}) in ${namespace} deployment exists`)
669
+ await this._k8sAppApi.readNamespacedDeployment({ name: project.safeName, namespace })
662
670
  this._app.log.info(`[k8s] deployment ${project.id} in ${namespace} found`)
663
671
  } catch (err) {
664
672
  this._app.log.error(`[k8s] Error while reading namespaced deployment for project '${project.safeName}' ${project.id}. Error msg=${err.message}, stack=${err.stack}`)
@@ -670,7 +678,7 @@ module.exports = {
670
678
  try {
671
679
  // pod already running
672
680
  this._app.log.info(`[k8s] Testing ${project.id} in ${namespace} pod exists`)
673
- await this._k8sApi.readNamespacedPodStatus(project.safeName, namespace)
681
+ await this._k8sApi.readNamespacedPodStatus({ name: project.safeName, namespace })
674
682
  this._app.log.info(`[k8s] pod ${project.id} in ${namespace} found`)
675
683
  } catch (err) {
676
684
  this._app.log.debug(`[k8s] Instance ${project.id} - recreating deployment`)
@@ -695,7 +703,7 @@ module.exports = {
695
703
  try {
696
704
  this._app.log.info(`[k8s] Testing MQTT Agent ${broker.hashid} in ${namespace} pod exists`)
697
705
  this._app.log.debug(`mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}`)
698
- await this._k8sApi.readNamespacedPodStatus(`mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}`, namespace)
706
+ await this._k8sApi.readNamespacedPodStatus({ name: `mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}`, namespace })
699
707
  this._app.log.info(`[k8s] MQTT Agent pod ${broker.hashid} in ${namespace} found`)
700
708
  } catch (err) {
701
709
  this._app.log.debug(`[k8s] MQTT Agent ${broker.hashid} - failed ${err.toString()}`)
@@ -765,31 +773,31 @@ module.exports = {
765
773
  this._projects[project.id].state = 'stopping'
766
774
 
767
775
  try {
768
- await this._k8sNetApi.deleteNamespacedIngress(project.safeName, this._namespace)
776
+ await this._k8sNetApi.deleteNamespacedIngress({ name: project.safeName, namespace: this._namespace })
769
777
  } catch (err) {
770
- this._app.log.error(`[k8s] Instance ${project.id} - error deleting ingress: ${err.toString()}`)
778
+ this._app.log.error(`[k8s] Instance ${project.id} - error deleting ingress: ${err.toString()} ${err.stack}`)
771
779
  }
772
780
 
773
781
  if (this._certManagerIssuer) {
774
782
  try {
775
- await this._k8sApi.deleteNamespacedSecret(project.safeName, this._namespace)
783
+ await this._k8sApi.deleteNamespacedSecret({ name: project.safeName, namespace: this._namespace })
776
784
  } catch (err) {
777
- this._app.log.error(`[k8s] Instance ${project.id} - error deleting tls secret: ${err.toString()}`)
785
+ this._app.log.error(`[k8s] Instance ${project.id} - error deleting tls secret: ${err.toString()} ${err.stack}`)
778
786
  }
779
787
  }
780
788
 
781
789
  if (this._customHostname?.enabled) {
782
790
  try {
783
- await this._k8sNetApi.deleteNamespacedIngress(`${project.safeName}-custom`, this._namespace)
791
+ await this._k8sNetApi.deleteNamespacedIngress({ name: `${project.safeName}-custom`, namespace: this._namespace })
784
792
  } catch (err) {
785
- this._app.log.error(`[k8s] Instance ${project.id} - error deleting custom ingress: ${err.toString()}`)
793
+ this._app.log.error(`[k8s] Instance ${project.id} - error deleting custom ingress: ${err.toString()} ${err.stack}`)
786
794
  }
787
795
 
788
796
  if (this._customHostname?.certManagerIssuer) {
789
797
  try {
790
- await this._k8sApi.deleteNamespacedSecret(`${project.safeName}-custom`, this._namespace)
798
+ await this._k8sApi.deleteNamespacedSecret({ name: `${project.safeName}-custom`, namespace: this._namespace })
791
799
  } catch (err) {
792
- this._app.log.error(`[k8s] Instance ${project.id} - error deleting custom tls secret: ${err.toString()}`)
800
+ this._app.log.error(`[k8s] Instance ${project.id} - error deleting custom tls secret: ${err.toString()} ${err.stack}`)
793
801
  }
794
802
  }
795
803
  }
@@ -802,7 +810,7 @@ module.exports = {
802
810
  let counter = 0
803
811
  const pollInterval = setInterval(async () => {
804
812
  try {
805
- await this._k8sNetApi.readNamespacedIngress(project.safeName, this._namespace)
813
+ await this._k8sNetApi.readNamespacedIngress({ name: project.safeName, namespace: this._namespace })
806
814
  } catch (err) {
807
815
  clearInterval(pollInterval)
808
816
  resolve()
@@ -821,9 +829,9 @@ module.exports = {
821
829
 
822
830
  const prefix = project.safeName.match(/^[0-9]/) ? 'srv-' : ''
823
831
  try {
824
- await this._k8sApi.deleteNamespacedService(prefix + project.safeName, this._namespace)
832
+ await this._k8sApi.deleteNamespacedService({ name: prefix + project.safeName, namespace: this._namespace })
825
833
  } catch (err) {
826
- this._app.log.error(`[k8s] Instance ${project.id} - error deleting service: ${err.toString()}`)
834
+ this._app.log.error(`[k8s] Instance ${project.id} - error deleting service: ${err.toString()} ${err.stack}`)
827
835
  }
828
836
 
829
837
  try {
@@ -831,7 +839,7 @@ module.exports = {
831
839
  let counter = 0
832
840
  const pollInterval = setInterval(async () => {
833
841
  try {
834
- await this._k8sApi.readNamespacedService(prefix + project.safeName, this._namespace)
842
+ await this._k8sApi.readNamespacedService({ name: prefix + project.safeName, namespace: this._namespace })
835
843
  } catch (err) {
836
844
  clearInterval(pollInterval)
837
845
  resolve()
@@ -845,16 +853,16 @@ module.exports = {
845
853
  }, this._k8sDelay)
846
854
  })
847
855
  } catch (err) {
848
- this._app.log.error(`[k8s] Instance ${project.id} - Service was not deleted: ${err.toString()}`)
856
+ this._app.log.error(`[k8s] Instance ${project.id} - Service was not deleted: ${err.toString()} ${err.stack}`)
849
857
  }
850
858
 
851
859
  const currentType = await project.getSetting('k8sType')
852
860
  let pod = true
853
861
  if (currentType === 'deployment') {
854
- await this._k8sAppApi.deleteNamespacedDeployment(project.safeName, this._namespace)
862
+ await this._k8sAppApi.deleteNamespacedDeployment({ name: project.safeName, namespace: this._namespace })
855
863
  pod = false
856
864
  } else {
857
- await this._k8sApi.deleteNamespacedPod(project.safeName, this._namespace)
865
+ await this._k8sApi.deleteNamespacedPod({ name: project.safeName, namespace: this._namespace })
858
866
  }
859
867
 
860
868
  // We should not delete the PVC when the instance is suspended
@@ -872,9 +880,9 @@ module.exports = {
872
880
  const pollInterval = setInterval(async () => {
873
881
  try {
874
882
  if (pod) {
875
- await this._k8sApi.readNamespacedPodStatus(project.safeName, this._namespace)
883
+ await this._k8sApi.readNamespacedPodStatus({ name: project.safeName, namespace: this._namespace })
876
884
  } else {
877
- await this._k8sAppApi.readNamespacedDeployment(project.safeName, this._namespace)
885
+ await this._k8sAppApi.readNamespacedDeployment({ name: project.safeName, namespace: this._namespace })
878
886
  }
879
887
  counter++
880
888
  if (counter > this._k8sRetries) {
@@ -897,26 +905,26 @@ module.exports = {
897
905
  */
898
906
  remove: async (project) => {
899
907
  try {
900
- await this._k8sNetApi.deleteNamespacedIngress(project.safeName, this._namespace)
908
+ await this._k8sNetApi.deleteNamespacedIngress({ name: project.safeName, namespace: this._namespace })
901
909
  } catch (err) {
902
910
  this._app.log.error(`[k8s] Instance ${project.id} - error deleting ingress: ${err.toString()}`)
903
911
  }
904
912
  if (this._certManagerIssuer) {
905
913
  try {
906
- await this._k8sApi.deleteNamespacedSecret(project.safeName, this._namespace)
914
+ await this._k8sApi.deleteNamespacedSecret({ name: project.safeName, namespace: this._namespace })
907
915
  } catch (err) {
908
916
  this._app.log.error(`[k8s] Instance ${project.id} - error deleting tls secret: ${err.toString()}`)
909
917
  }
910
918
  }
911
919
  if (this._customHostname?.enabled) {
912
920
  try {
913
- await this._k8sNetApi.deleteNamespacedIngress(`${project.safeName}-custom`, this._namespace)
921
+ await this._k8sNetApi.deleteNamespacedIngress({ name: `${project.safeName}-custom`, namespace: this._namespace })
914
922
  } catch (err) {
915
923
  this._app.log.error(`[k8s] Instance ${project.id} - error deleting custom ingress: ${err.toString()}`)
916
924
  }
917
925
  if (this._customHostname?.certManagerIssuer) {
918
926
  try {
919
- await this._k8sApi.deleteNamespacedSecret(`${project.safeName}-custom`, this._namespace)
927
+ await this._k8sApi.deleteNamespacedSecret({ name: `${project.safeName}-custom`, namespace: this._namespace })
920
928
  } catch (err) {
921
929
  this._app.log.error(`[k8s] Instance ${project.id} - error deleting custom tls secret: ${err.toString()}`)
922
930
  }
@@ -924,9 +932,9 @@ module.exports = {
924
932
  }
925
933
  try {
926
934
  if (project.safeName.match(/^[0-9]/)) {
927
- await this._k8sApi.deleteNamespacedService('srv-' + project.safeName, this._namespace)
935
+ await this._k8sApi.deleteNamespacedService({ name: 'srv-' + project.safeName, namespace: this._namespace })
928
936
  } else {
929
- await this._k8sApi.deleteNamespacedService(project.safeName, this._namespace)
937
+ await this._k8sApi.deleteNamespacedService({ name: project.safeName, namespace: this._namespace })
930
938
  }
931
939
  } catch (err) {
932
940
  this._app.log.error(`[k8s] Instance ${project.id} - error deleting service: ${err.toString()}`)
@@ -936,9 +944,9 @@ module.exports = {
936
944
  // A suspended project won't have a pod to delete - but try anyway
937
945
  // just in case state has got out of sync
938
946
  if (currentType === 'deployment') {
939
- await this._k8sAppApi.deleteNamespacedDeployment(project.safeName, this._namespace)
947
+ await this._k8sAppApi.deleteNamespacedDeployment({ name: project.safeName, namespace: this._namespace })
940
948
  } else {
941
- await this._k8sApi.deleteNamespacedPod(project.safeName, this._namespace)
949
+ await this._k8sApi.deleteNamespacedPod({ name: project.safeName, namespace: this._namespace })
942
950
  }
943
951
  } catch (err) {
944
952
  if (project.state !== 'suspended') {
@@ -951,9 +959,9 @@ module.exports = {
951
959
  }
952
960
  if (this._app.config.driver.options?.storage?.enabled) {
953
961
  try {
954
- await this._k8sApi.deleteNamespacedPersistentVolumeClaim(`${project.id}-pvc`, this._namespace)
962
+ await this._k8sApi.deleteNamespacedPersistentVolumeClaim({ name: `${project.id}-pvc`, namespace: this._namespace })
955
963
  } catch (err) {
956
- this._app.log.error(`[k8s] Instance ${project.id} - error deleting PVC: ${err.toString()} ${err.statusCode}`)
964
+ this._app.log.error(`[k8s] Instance ${project.id} - error deleting PVC: ${err.toString()} ${err.code}`)
957
965
  // console.log(err)
958
966
  }
959
967
  }
@@ -983,8 +991,8 @@ module.exports = {
983
991
  const currentType = await project.getSetting('k8sType')
984
992
  try {
985
993
  if (currentType === 'deployment') {
986
- details = await this._k8sAppApi.readNamespacedDeployment(project.safeName, this._namespace)
987
- if (details.body.status?.conditions[0].status === 'False') {
994
+ details = await this._k8sAppApi.readNamespacedDeployment({ name: project.safeName, namespace: this._namespace })
995
+ if (details.status?.conditions[0].status === 'False') {
988
996
  // return "starting" status until pod it running
989
997
  this._projects[project.id].state = 'starting'
990
998
  return {
@@ -992,14 +1000,14 @@ module.exports = {
992
1000
  state: 'starting',
993
1001
  meta: {}
994
1002
  }
995
- } else if (details.body.status?.conditions[0].status === 'True' &&
996
- (details.body.status?.conditions[0].type === 'Available' ||
997
- (details.body.status?.conditions[0].type === 'Progressing' && details.body.status?.conditions[0].reason === 'NewReplicaSetAvailable')
1003
+ } else if (details.status?.conditions[0].status === 'True' &&
1004
+ (details.status?.conditions[0].type === 'Available' ||
1005
+ (details.status?.conditions[0].type === 'Progressing' && details.status?.conditions[0].reason === 'NewReplicaSetAvailable')
998
1006
  )) {
999
1007
  // not calling all endpoints for HA as they should be the same
1000
1008
  const infoURL = `http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/info`
1001
1009
  try {
1002
- const info = JSON.parse((await got.get(infoURL)).body)
1010
+ const info = JSON.parse((await got.get(infoURL, { timeout: { request: 1000 } })).body)
1003
1011
  this._projects[project.id].state = info.state
1004
1012
  return info
1005
1013
  } catch (err) {
@@ -1014,13 +1022,13 @@ module.exports = {
1014
1022
  return {
1015
1023
  id: project.id,
1016
1024
  state: 'starting',
1017
- error: `Unexpected pod status '${details.body.status?.conditions[0]?.status}', type '${details.body.status?.conditions[0]?.type}'`,
1025
+ error: `Unexpected pod status '${details.status?.conditions[0]?.status}', type '${details.status?.conditions[0]?.type}'`,
1018
1026
  meta: {}
1019
1027
  }
1020
1028
  }
1021
1029
  } else {
1022
- details = await this._k8sApi.readNamespacedPodStatus(project.safeName, this._namespace)
1023
- if (details.body.status?.phase === 'Pending') {
1030
+ details = await this._k8sApi.readNamespacedPodStatus({ name: project.safeName, namespace: this._namespace })
1031
+ if (details.status?.phase === 'Pending') {
1024
1032
  // return "starting" status until pod it running
1025
1033
  this._projects[project.id].state = 'starting'
1026
1034
  return {
@@ -1028,11 +1036,11 @@ module.exports = {
1028
1036
  state: 'starting',
1029
1037
  meta: {}
1030
1038
  }
1031
- } else if (details.body.status?.phase === 'Running') {
1039
+ } else if (details.status?.phase === 'Running') {
1032
1040
  // not calling all endpoints for HA as they should be the same
1033
1041
  const infoURL = `http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/info`
1034
1042
  try {
1035
- const info = JSON.parse((await got.get(infoURL)).body)
1043
+ const info = JSON.parse((await got.get(infoURL, { timeout: { request: 1000 } })).body)
1036
1044
  this._projects[project.id].state = info.state
1037
1045
  return info
1038
1046
  } catch (err) {
@@ -1047,18 +1055,18 @@ module.exports = {
1047
1055
  return {
1048
1056
  id: project.id,
1049
1057
  state: 'starting',
1050
- error: `Unexpected pod status '${details.body.status?.phase}'`,
1058
+ error: `Unexpected pod status '${details.status?.phase}'`,
1051
1059
  meta: {}
1052
1060
  }
1053
1061
  }
1054
1062
  }
1055
1063
  } catch (err) {
1056
- this._app.log.debug(`error getting pod status for instance ${project.id}: ${err}`)
1064
+ this._app.log.debug(`error getting pod status for instance ${project.id}: ${err} ${err.stack}`)
1057
1065
  return {
1058
1066
  id: project?.id,
1059
1067
  error: err,
1060
1068
  state: 'starting',
1061
- meta: details?.body?.status
1069
+ meta: details?.status
1062
1070
  }
1063
1071
  }
1064
1072
  },
@@ -1134,7 +1142,7 @@ module.exports = {
1134
1142
  const addresses = await getEndpoints(project)
1135
1143
  const logRequests = []
1136
1144
  for (const address in addresses) {
1137
- logRequests.push(got.get(`http://${addresses[address]}:2880/flowforge/logs`).json())
1145
+ logRequests.push(got.get(`http://${addresses[address]}:2880/flowforge/logs`, { timeout: { request: 1000 } }).json())
1138
1146
  }
1139
1147
  const results = await Promise.all(logRequests)
1140
1148
  const combinedResults = results.flat(1)
@@ -1142,7 +1150,7 @@ module.exports = {
1142
1150
  return combinedResults
1143
1151
  } else {
1144
1152
  const prefix = project.safeName.match(/^[0-9]/) ? 'srv-' : ''
1145
- const result = await got.get(`http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/logs`).json()
1153
+ const result = await got.get(`http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/logs`, { timeout: { request: 1000 } }).json()
1146
1154
  return result
1147
1155
  }
1148
1156
  },
@@ -1213,7 +1221,7 @@ module.exports = {
1213
1221
  listFiles: async (instance, filePath) => {
1214
1222
  const fileUrl = await getStaticFileUrl(instance, filePath)
1215
1223
  try {
1216
- return got.get(fileUrl).json()
1224
+ return got.get(fileUrl, { timeout: { request: 1000 } }).json()
1217
1225
  } catch (err) {
1218
1226
  console.log(err)
1219
1227
  err.statusCode = err.response.statusCode
@@ -1273,15 +1281,15 @@ module.exports = {
1273
1281
  },
1274
1282
  stopBrokerAgent: async (broker) => {
1275
1283
  try {
1276
- await this._k8sApi.deleteNamespacedService(`mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}`, this._namespace)
1277
- await this._k8sApi.deleteNamespacedPod(`mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}`, this._namespace)
1284
+ await this._k8sApi.deleteNamespacedService({ name: `mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}`, namespace: this._namespace })
1285
+ await this._k8sApi.deleteNamespacedPod({ name: `mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}`, namespace: this._namespace })
1278
1286
  } catch (err) {
1279
- this._app.log.error(`[k8s] Error deleting MQTT Agent ${broker.hashid}: ${err.toString()} ${err.statusCode}`)
1287
+ this._app.log.error(`[k8s] Error deleting MQTT Agent ${broker.hashid}: ${err.toString()} ${err.code}`)
1280
1288
  }
1281
1289
  },
1282
1290
  getBrokerAgentState: async (broker) => {
1283
1291
  try {
1284
- const status = await got.get(`http://mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}.${this._namespace}:3500/api/v1/status`).json()
1292
+ const status = await got.get(`http://mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}.${this._namespace}:3500/api/v1/status`, { timeout: { request: 1000 } }).json()
1285
1293
  return status
1286
1294
  } catch (err) {
1287
1295
  return { error: 'error_getting_status', message: err.toString() }
@@ -1290,13 +1298,13 @@ module.exports = {
1290
1298
  sendBrokerAgentCommand: async (broker, command) => {
1291
1299
  if (command === 'start' || command === 'restart') {
1292
1300
  try {
1293
- await got.post(`http://mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}.${this._namespace}:3500/api/v1/commands/start`)
1301
+ await got.post(`http://mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}.${this._namespace}:3500/api/v1/commands/start`, { timeout: { request: 1000 } })
1294
1302
  } catch (err) {
1295
1303
 
1296
1304
  }
1297
1305
  } else if (command === 'stop') {
1298
1306
  try {
1299
- await got.post(`http://mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}.${this._namespace}:3500/api/v1/commands/stop`)
1307
+ await got.post(`http://mqtt-schema-agent-${broker.Team.hashid.toLowerCase()}-${broker.hashid.toLowerCase()}.${this._namespace}:3500/api/v1/commands/stop`, { timeout: { request: 1000 } })
1300
1308
  } catch (err) {
1301
1309
 
1302
1310
  }
@@ -1325,7 +1333,7 @@ module.exports = {
1325
1333
  }
1326
1334
  } else {
1327
1335
  const prefix = project.safeName.match(/^[0-9]/) ? 'srv-' : ''
1328
- const result = await got.get(`http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/resources`).json()
1336
+ const result = await got.get(`http://${prefix}${project.safeName}.${this._namespace}:2880/flowforge/resources`, { timeout: { request: 1000 } }).json()
1329
1337
  if (Array.isArray(result)) {
1330
1338
  return {
1331
1339
  meta: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowfuse/driver-kubernetes",
3
- "version": "2.21.1",
3
+ "version": "2.21.2-057ae7d-202509080755.0",
4
4
  "description": "Kubernetes driver for FlowFuse",
5
5
  "main": "kubernetes.js",
6
6
  "scripts": {
@@ -22,7 +22,7 @@
22
22
  "license": "Apache-2.0",
23
23
  "dependencies": {
24
24
  "@aws-sdk/client-efs": "^3.600.0",
25
- "@kubernetes/client-node": "^0.22.3",
25
+ "@kubernetes/client-node": "^1.3.0",
26
26
  "form-data": "^4.0.0",
27
27
  "got": "^11.8.0",
28
28
  "lodash": "^4.17.21"