@flowfuse/driver-kubernetes 2.21.1-f8d2ace-202508280935.0 → 2.21.2-7715822-202509040953.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.
- package/CHANGELOG.md +4 -0
- package/kubernetes.js +89 -81
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
557
|
-
await this._k8sApi.
|
|
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.
|
|
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.
|
|
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.
|
|
996
|
-
(details.
|
|
997
|
-
(details.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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?.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
3
|
+
"version": "2.21.2-7715822-202509040953.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": "^
|
|
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"
|