"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.kubedriver = void 0;
const openflow_api_1 = require("@openiap/openflow-api");
const Logger_1 = require("../Logger");
const Crypt_1 = require("../Crypt");
const Config_1 = require("../Config");
const client_node_1 = require("@kubernetes/client-node");
const KubeUtil_1 = require("./KubeUtil");
const url = require("url");
const Audit_1 = require("../Audit");
class kubedriver {
    async detect() {
        try {
            var lic = Logger_1.Logger.License;
            if (!Logger_1.Logger.License)
                return false;
            if (!Logger_1.Logger.License.validate)
                return false;
            Logger_1.Logger.License.validate();
        }
        catch (error) {
            if (error.message != "Missing license_key") {
                Logger_1.Logger.instanse.error("kubedriver", "detect", error.message ? error.message : error);
            }
            return false;
        }
        if (!Logger_1.Logger.License.validlicense)
            return false;
        return true;
    }
    async EnsureNoderedInstance(jwt, tokenUser, _id, name, skipcreate, parent) {
        let user;
        const span = Logger_1.Logger.otel.startSubSpan("message.EnsureNoderedInstance", parent);
        try {
            if (_id === null || _id === undefined || _id === "")
                _id = tokenUser._id;
            Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] EnsureNoderedInstance for " + name + " in namespace " + Config_1.Config.namespace);
            const users = await Config_1.Config.db.query({ query: { _id: _id }, top: 1, collectionname: "users", jwt: jwt }, span);
            if (users.length == 0) {
                throw new Error("Unknown userid " + _id);
            }
            user = openflow_api_1.NoderedUser.assign(users[0]);
            const rootjwt = Crypt_1.Crypt.rootToken();
            const namespace = Config_1.Config.namespace;
            let nodered_domain_schema = Config_1.Config.nodered_domain_schema;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(nodered_domain_schema)) {
                nodered_domain_schema = "$nodered_id$." + Config_1.Config.domain;
            }
            const hostname = nodered_domain_schema.replace("$nodered_id$", name);
            const nodereduser = await Logger_1.Logger.DBHelper.FindById(_id, jwt, span);
            const tuser = openflow_api_1.TokenUser.From(nodereduser);
            const nodered_jwt = Crypt_1.Crypt.createToken(tuser, Config_1.Config.personalnoderedtoken_expires_in);
            await Logger_1.Logger.DBHelper.EnsureNoderedRoles(tuser, jwt, true, span);
            const resources = new client_node_1.V1ResourceRequirements();
            let hasbilling = false;
            resources.limits = {};
            resources.requests = {};
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.nodered_requests_memory))
                resources.requests.memory = Config_1.Config.nodered_requests_memory;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.nodered_requests_cpu))
                resources.requests.cpu = Config_1.Config.nodered_requests_cpu;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.nodered_limits_memory))
                resources.limits.memory = Config_1.Config.nodered_limits_memory;
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.nodered_limits_cpu))
                resources.limits.cpu = Config_1.Config.nodered_limits_cpu;
            let nodered_image_name = Config_1.Config.nodered_images[0].name;
            let tzvolume = null;
            let tz = undefined;
            if (user.nodered) {
                try {
                    if (user.nodered.api_allow_anonymous == null)
                        user.nodered.api_allow_anonymous = false;
                    if (user.nodered.function_external_modules == null)
                        user.nodered.function_external_modules = false;
                    if (user.nodered.nodered_image_name == null)
                        user.nodered.nodered_image_name = nodered_image_name;
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(user.nodered.tz)) {
                        tz = user.nodered.tz;
                        tzvolume = {
                            name: "tz",
                            hostPath: {
                                path: "/usr/share/zoneinfo/" + user.nodered.tz
                            }
                        };
                    }
                }
                catch (error) {
                    user.nodered = { api_allow_anonymous: false, function_external_modules: false, nodered_image_name };
                }
            }
            else {
                user.nodered = { api_allow_anonymous: false, function_external_modules: false, nodered_image_name };
            }
            const _nodered_image = Config_1.Config.nodered_images.filter(x => x.name == user.nodered.nodered_image_name);
            let nodered_image = Config_1.Config.nodered_images[0].image;
            if (_nodered_image.length == 1) {
                nodered_image = _nodered_image[0].image;
            }
            let planNodeSelector = null;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.stripe_api_secret) && !Config_1.Config.multi_tenant) {
                if (user.nodered && user.nodered.resources) {
                    if (user.nodered.resources.limits) {
                        resources.limits.memory = user.nodered.resources.limits.memory;
                        resources.limits.cpu = user.nodered.resources.limits.cpu;
                        resources.requests.memory = user.nodered.resources.limits.memory;
                        resources.requests.cpu = user.nodered.resources.limits.cpu;
                    }
                    if (user.nodered.resources.requests) {
                        resources.requests.memory = user.nodered.resources.requests.memory;
                        resources.requests.cpu = user.nodered.resources.requests.cpu;
                    }
                }
            }
            else {
                let _resources = await Config_1.Config.db.db.collection("config").
                    find({ "_type": "resource", "name": "Nodered Instance" }).toArray();
                if (_resources.length > 0) {
                    let resource = _resources[0];
                    if (resource.defaultmetadata.resources) {
                        if (resource.defaultmetadata.resources.limits) {
                            if (resource.defaultmetadata.resources.limits.memory)
                                resources.limits.memory = resource.defaultmetadata.resources.limits.memory;
                            if (resource.defaultmetadata.resources.limits.cpu)
                                resources.limits.cpu = resource.defaultmetadata.resources.limits.cpu;
                        }
                        if (resource.defaultmetadata.resources.requests) {
                            if (resource.defaultmetadata.resources.requests.memory)
                                resources.requests.memory = resource.defaultmetadata.resources.requests.memory;
                            if (resource.defaultmetadata.resources.requests.cpu)
                                resources.requests.cpu = resource.defaultmetadata.resources.requests.cpu;
                        }
                    }
                    if (resource.defaultmetadata.NodeSelector || resource.defaultmetadata.nodeSelector) {
                        planNodeSelector = resource.defaultmetadata.NodeSelector || resource.defaultmetadata.nodeSelector;
                    }
                    let assigned = await Config_1.Config.db.db.collection("config")
                        .find({ "_type": "resourceusage", "userid": user._id, "resource": "Nodered Instance" }).toArray();
                    if (assigned.length > 0) {
                        let usage = assigned[0];
                        if (usage.quantity > 0 && !openflow_api_1.NoderedUtil.IsNullEmpty(usage.siid)) {
                            hasbilling = true;
                            if (usage.product.metadata.resources) {
                                if (usage.product.metadata.resources.limits) {
                                    if (usage.product.metadata.resources.limits.memory)
                                        resources.limits.memory = usage.product.metadata.resources.limits.memory;
                                    if (usage.product.metadata.resources.limits.cpu)
                                        resources.limits.cpu = usage.product.metadata.resources.limits.cpu;
                                }
                                if (usage.product.metadata.resources.requests) {
                                    if (usage.product.metadata.resources.requests.memory)
                                        resources.requests.memory = usage.product.metadata.resources.requests.memory;
                                    if (usage.product.metadata.resources.requests.cpu)
                                        resources.requests.cpu = usage.product.metadata.resources.requests.cpu;
                                }
                            }
                            if (usage.product.metadata.NodeSelector || usage.product.metadata.nodeSelector) {
                                planNodeSelector = usage.product.metadata.NodeSelector || usage.product.metadata.nodeSelector;
                            }
                        }
                    }
                }
            }
            var port = 3000;
            let livenessProbe = {
                httpGet: {
                    path: "/livenessprobe",
                    port: 3000,
                    scheme: "HTTP"
                },
                initialDelaySeconds: Config_1.Config.nodered_initial_liveness_delay,
                periodSeconds: 5,
                failureThreshold: Config_1.Config.nodered_liveness_failurethreshold,
                timeoutSeconds: Config_1.Config.nodered_liveness_timeoutseconds
            };
            if (user.nodered && user.nodered.livenessProbe) {
                livenessProbe = user.nodered.livenessProbe;
            }
            Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tuser.username + "] GetDeployments");
            const deployment = await KubeUtil_1.KubeUtil.instance().GetDeployment(namespace, name);
            if (deployment == null) {
                if (skipcreate)
                    return;
                Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tuser.username + "] Deployment " + name + " not found in " + namespace + " so creating it");
                let api_ws_url = Config_1.Config.basewsurl();
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.api_ws_url))
                    api_ws_url = Config_1.Config.api_ws_url;
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.nodered_ws_url))
                    api_ws_url = Config_1.Config.nodered_ws_url;
                if (!api_ws_url.endsWith("/"))
                    api_ws_url += "/";
                var port = 3000;
                let saml_baseurl = Config_1.Config.protocol + "://" + hostname + "/";
                var saml_federation_metadata = Config_1.Config.saml_federation_metadata;
                if (saml_federation_metadata == "https://pc.openiap.io/issue/FederationMetadata/2007-06/FederationMetadata.xml") {
                    saml_federation_metadata = "https://demo.openiap.io/issue/FederationMetadata/2007-06/FederationMetadata.xml";
                }
                let _api_ws_parsed = url.parse(api_ws_url);
                //if (_samlparsed.protocol == "http:" || _samlparsed.protocol == "ws:") {
                if (_api_ws_parsed.protocol == "http" || _api_ws_parsed.protocol == "ws") {
                    saml_baseurl = "http://" + hostname;
                    if (_api_ws_parsed.port && _api_ws_parsed.port != "80" && _api_ws_parsed.port != "3000") {
                        saml_baseurl += ":" + _api_ws_parsed.port;
                    }
                }
                else {
                    saml_baseurl = "https://" + hostname;
                    if (_api_ws_parsed.port && _api_ws_parsed.port != "443" && _api_ws_parsed.port != "3000") {
                        saml_baseurl += ":" + _api_ws_parsed.port;
                    }
                }
                saml_baseurl += "/";
                if (!openflow_api_1.NoderedUtil.IsNullUndefinded(resources.limits) && openflow_api_1.NoderedUtil.IsNullEmpty(resources.limits.memory))
                    delete resources.limits.memory;
                if (!openflow_api_1.NoderedUtil.IsNullUndefinded(resources.limits) && openflow_api_1.NoderedUtil.IsNullEmpty(resources.limits.cpu))
                    delete resources.limits.cpu;
                if (!openflow_api_1.NoderedUtil.IsNullUndefinded(resources.requests) && openflow_api_1.NoderedUtil.IsNullEmpty(resources.requests.memory))
                    delete resources.requests.memory;
                if (!openflow_api_1.NoderedUtil.IsNullUndefinded(resources.requests) && openflow_api_1.NoderedUtil.IsNullEmpty(resources.requests.memory))
                    delete resources.requests.memory;
                if (api_ws_url == "wss://pc.openiap.io/") {
                    api_ws_url = "wss://demo.openiap.io/";
                }
                var nodered_saml_entrypoint = saml_federation_metadata.split("/FederationMetadata/2007-06/FederationMetadata.xml").join("");
                if (!openflow_api_1.NoderedUtil.IsNullEmpty(Config_1.Config.nodered_saml_entrypoint))
                    nodered_saml_entrypoint = Config_1.Config.nodered_saml_entrypoint;
                const _deployment = {
                    metadata: { name: name, namespace: namespace, labels: { billed: hasbilling.toString(), userid: _id, app: name } },
                    spec: {
                        replicas: 1,
                        selector: { matchLabels: { app: name } },
                        template: {
                            metadata: { labels: { name: name, app: name, billed: hasbilling.toString(), userid: _id } },
                            spec: {
                                volumes: [],
                                containers: [
                                    {
                                        name: 'nodered',
                                        image: nodered_image,
                                        imagePullPolicy: "Always",
                                        ports: [{ containerPort: port }, { containerPort: 5859 }],
                                        resources: resources,
                                        volumeMounts: [],
                                        env: [
                                            { name: "saml_federation_metadata", value: saml_federation_metadata },
                                            { name: "saml_issuer", value: Config_1.Config.saml_issuer },
                                            { name: "saml_baseurl", value: saml_baseurl },
                                            { name: "saml_entrypoint", value: nodered_saml_entrypoint },
                                            { name: "nodered_id", value: name },
                                            { name: "nodered_sa", value: nodereduser.username },
                                            { name: "jwt", value: nodered_jwt },
                                            { name: "queue_prefix", value: user.nodered.queue_prefix },
                                            { name: "api_ws_url", value: api_ws_url },
                                            { name: "domain", value: hostname },
                                            { name: "protocol", value: Config_1.Config.protocol },
                                            { name: "port", value: port.toString() },
                                            { name: "noderedusers", value: (name + "noderedusers") },
                                            { name: "noderedadmins", value: (name + "noderedadmins") },
                                            { name: "noderedapiusers", value: (name + "nodered api users") },
                                            { name: "api_allow_anonymous", value: user.nodered.api_allow_anonymous.toString() },
                                            { name: "function_external_modules", value: user.nodered.function_external_modules.toString() },
                                            { name: "prometheus_measure_nodeid", value: Config_1.Config.prometheus_measure_nodeid.toString() },
                                            { name: "prometheus_measure_queued_messages", value: Config_1.Config.prometheus_measure_queued_messages.toString() },
                                            { name: "NODE_ENV", value: Config_1.Config.NODE_ENV },
                                            { name: "HTTP_PROXY", value: Config_1.Config.HTTP_PROXY },
                                            { name: "HTTPS_PROXY", value: Config_1.Config.HTTPS_PROXY },
                                            { name: "NO_PROXY", value: Config_1.Config.NO_PROXY },
                                            { name: "prometheus_expose_metric", value: "false" },
                                            { name: "enable_analytics", value: Config_1.Config.enable_analytics.toString() },
                                            { name: "tours", value: Config_1.Config.enable_nodered_tours.toString() },
                                            { name: "otel_trace_url", value: Config_1.Config.otel_trace_url },
                                            { name: "otel_metric_url", value: Config_1.Config.otel_metric_url },
                                            { name: "otel_trace_interval", value: Config_1.Config.otel_trace_interval.toString() },
                                            { name: "otel_metric_interval", value: Config_1.Config.otel_metric_interval.toString() },
                                            { name: "otel_debug_log", value: Config_1.Config.otel_debug_log.toString() },
                                            { name: "otel_warn_log", value: Config_1.Config.otel_warn_log.toString() },
                                            { name: "otel_err_log", value: Config_1.Config.otel_err_log.toString() },
                                            { name: "amqp_enabled_exchange", value: Config_1.Config.amqp_enabled_exchange.toString() },
                                            { name: "noderedcatalogues", value: Config_1.Config.noderedcatalogues },
                                            { name: "log_with_colors", value: Config_1.Config.log_with_colors.toString() },
                                            { name: "TZ", value: tz },
                                        ],
                                        livenessProbe: livenessProbe,
                                    }
                                ]
                            }
                        }
                    }
                };
                if (tzvolume != null) {
                    _deployment.spec.template.spec.volumes.push(tzvolume);
                    _deployment.spec.template.spec.containers[0].volumeMounts.push({ "name": "tz", "mountPath": "/etc/localtime" });
                }
                if (user.nodered && user.nodered.nodeselector && Config_1.Config.nodered_allow_nodeselector) {
                    var spec = _deployment.spec.template.spec;
                    const keys = Object.keys(user.nodered.nodeselector);
                    if (spec.nodeSelector == null)
                        spec.nodeSelector = {};
                    keys.forEach(key => {
                        spec.nodeSelector[key] = user.nodered.nodeselector[key];
                    });
                }
                if (planNodeSelector != null) {
                    var spec = _deployment.spec.template.spec;
                    const keys = Object.keys(planNodeSelector);
                    if (spec.nodeSelector == null)
                        spec.nodeSelector = {};
                    keys.forEach(key => {
                        let newkey = key.split("____").join(".");
                        spec.nodeSelector[newkey] = (planNodeSelector[key]);
                    });
                }
                try {
                    await KubeUtil_1.KubeUtil.instance().AppsV1Api.createNamespacedDeployment(namespace, _deployment);
                    await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(tuser), true, name, "createdeployment", nodered_image, null, span);
                }
                catch (error) {
                    if (error.response && error.response.body && error.response.body.message) {
                        Logger_1.Logger.instanse.error("kubedriver", "EnsureNoderedInstance", new Error(error.response.body.message));
                        throw new Error(error.response.body.message);
                    }
                    await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(tuser), false, name, "createdeployment", nodered_image, null, span);
                    throw error;
                }
            }
            else {
                deployment.spec.template.spec.containers[0].resources = resources;
                const f = deployment.spec.template.spec.containers[0].env.filter(x => x.name == "api_allow_anonymous");
                if (f.length > 0) {
                    f[0].value = user.nodered.api_allow_anonymous.toString();
                }
                deployment.metadata.labels.billed = hasbilling.toString();
                deployment.spec.template.metadata.labels.billed = hasbilling.toString();
                deployment.metadata.labels.userid = _id;
                deployment.spec.template.metadata.labels.userid = _id;
                let image = "unknown";
                try {
                    image = deployment.spec.template.spec.containers[0].image;
                }
                catch (error) {
                }
                try {
                    await KubeUtil_1.KubeUtil.instance().AppsV1Api.replaceNamespacedDeployment(name, namespace, deployment);
                    await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(tuser), true, name, "replacedeployment", image, null, span);
                }
                catch (error) {
                    Logger_1.Logger.instanse.error("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] failed updating noeredinstance");
                    Logger_1.Logger.instanse.error("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] " + JSON.stringify(error));
                    if (error.response && error.response.body && !openflow_api_1.NoderedUtil.IsNullEmpty(error.response.body.message)) {
                        Logger_1.Logger.instanse.error("kubedriver", "EnsureNoderedInstance", new Error(error.response.body.message));
                        throw new Error(error.response.body.message);
                    }
                    await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(tuser), false, name, "replacedeployment", image, null, span);
                    throw new Error("failed updating noeredinstance");
                }
            }
            let servicename = name;
            // /^(?!-)[a-zA-Z0-9-]{1,63}$/g;
            var test = /[a-z]([-a-z0-9]*[a-z0-9])?/.exec(servicename);
            if (test == null || test.index != 0) {
                servicename = "nr" + name + "svc";
            }
            Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tuser.username + "] GetService");
            const service = await KubeUtil_1.KubeUtil.instance().GetService(namespace, servicename);
            if (service == null) {
                Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] Service " + servicename + " not found in " + namespace + " creating it");
                const _service = {
                    metadata: { name: servicename, namespace: namespace },
                    spec: {
                        type: "NodePort",
                        sessionAffinity: "ClientIP",
                        selector: { app: name },
                        ports: [
                            { port: port, name: "www" }
                        ]
                    }
                };
                await KubeUtil_1.KubeUtil.instance().CoreV1Api.createNamespacedService(namespace, _service);
            }
            Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] GetIngress useringress");
            const ingress = await KubeUtil_1.KubeUtil.instance().GetIngressV1(namespace, "useringress");
            if (ingress !== null) {
                let rule = null;
                for (let i = 0; i < ingress.spec.rules.length; i++) {
                    if (ingress.spec.rules[i].host == hostname) {
                        rule = ingress.spec.rules[i];
                    }
                }
                if (rule == null) {
                    Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] ingress " + hostname + " not found in useringress creating it");
                    rule = {
                        host: hostname,
                        http: {
                            paths: [{
                                    path: "/",
                                    pathType: "Prefix",
                                    backend: {
                                        service: {
                                            name: servicename,
                                            port: {
                                                number: port
                                            }
                                        }
                                    }
                                }]
                        }
                    };
                    ingress.spec.rules.push(rule);
                    delete ingress.metadata.creationTimestamp;
                    delete ingress.status;
                    Logger_1.Logger.instanse.debug("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] replaceNamespacedIngress");
                    await KubeUtil_1.KubeUtil.instance().NetworkingV1Api.replaceNamespacedIngress("useringress", namespace, ingress);
                }
            }
            else {
                Logger_1.Logger.instanse.error("kubedriver", "EnsureNoderedInstance", "[" + tokenUser.username + "] failed locating useringress");
                throw new Error("failed locating useringress");
            }
        }
        catch (error) {
            if (error.response && error.response.body && error.response.body.message) {
                Logger_1.Logger.instanse.error("kubedriver", "EnsureNoderedInstance", new Error(error.response.body.message));
                error.message = error.response.body.message;
            }
            else if (error.response && error.response.body) {
                Logger_1.Logger.instanse.error("kubedriver", "EnsureNoderedInstance", new Error(error.response.body));
                error.message = error.response.body;
            }
            else {
                error.message = error.message ? error.message : error;
            }
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async GetNoderedInstance(jwt, tokenUser, _id, name, parent) {
        var _a;
        const span = Logger_1.Logger.otel.startSubSpan("message.GetNoderedInstance", parent);
        try {
            const noderedresource = await Config_1.Config.db.GetOne({ "collectionname": "config", "query": { "name": "Nodered Instance", "_type": "resource" } }, span);
            let runtime = (_a = noderedresource === null || noderedresource === void 0 ? void 0 : noderedresource.defaultmetadata) === null || _a === void 0 ? void 0 : _a.runtime_hours;
            const rootjwt = Crypt_1.Crypt.rootToken();
            const rootuser = openflow_api_1.TokenUser.From(Crypt_1.Crypt.rootUser());
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(runtime)) {
                // If nodered resource does not exists, dont turn off nodereds
                runtime = 0;
                // If nodered resource does exists, but have no default, use 24 hours
                if (!openflow_api_1.NoderedUtil.IsNullUndefinded(noderedresource))
                    runtime = 24;
            }
            const namespace = Config_1.Config.namespace;
            const list = await KubeUtil_1.KubeUtil.instance().CoreV1Api.listNamespacedPod(namespace);
            var results = [];
            if (list.body.items.length > 0) {
                let found = null;
                for (let i = 0; i < list.body.items.length; i++) {
                    const item = list.body.items[i];
                    if (!openflow_api_1.NoderedUtil.IsNullUndefinded(noderedresource) && runtime > 0) {
                        const itemname = item.metadata.name;
                        const create = item.metadata.creationTimestamp;
                        const billed = item.metadata.labels.billed;
                        const image = item.spec.containers[0].image;
                        const userid = item.metadata.labels.userid;
                        const app = item.metadata.labels.app;
                        const date = new Date();
                        const a = date - create;
                        // const diffminutes = a / (1000 * 60);
                        const diffhours = a / (1000 * 60 * 60);
                        if ((image.indexOf("openflownodered") > -1 || image.indexOf("openiap/nodered") > -1) && !openflow_api_1.NoderedUtil.IsNullEmpty(userid)) {
                            try {
                                if (billed != "true" && diffhours > runtime) {
                                    Logger_1.Logger.instanse.debug("kubedriver", "GetNoderedInstance", "[" + tokenUser.username + "] Remove un billed nodered instance " + app + " that has been running for " + diffhours + " hours");
                                    await this.DeleteNoderedInstance(rootjwt, rootuser, _id, app, span);
                                }
                            }
                            catch (error) {
                            }
                        }
                        else if (image.indexOf("openflownodered") > -1 || image.indexOf("openiap/nodered") > -1) {
                            if (billed != "true" && diffhours > runtime) {
                                Logger_1.Logger.instanse.info("kubedriver", "GetNoderedInstance", "unbilled " + itemname + " with no userid, should be removed, it has been running for " + diffhours + " hours");
                            }
                            else {
                                Logger_1.Logger.instanse.info("kubedriver", "GetNoderedInstance", "unbilled " + itemname + " with no userid, has been running for " + diffhours + " hours");
                            }
                        }
                    }
                    if (!openflow_api_1.NoderedUtil.IsNullEmpty(name) && item.metadata.name == name && tokenUser.HasRoleName("admins")) {
                        found = item;
                        var metrics = null;
                        try {
                            metrics = await KubeUtil_1.KubeUtil.instance().GetPodMetrics(namespace, item.metadata.name);
                            item.metrics = metrics;
                        }
                        catch (error) {
                        }
                        results.push(item);
                    }
                    else if (item.metadata.labels.app === name) {
                        found = item;
                        if (item.status.phase != "Failed") {
                        }
                        var metrics = null;
                        try {
                            metrics = await KubeUtil_1.KubeUtil.instance().GetPodMetrics(namespace, item.metadata.name);
                            item.metrics = metrics;
                        }
                        catch (error) {
                        }
                        results.push(item);
                    }
                }
            }
            else {
                Logger_1.Logger.instanse.warn("kubedriver", "GetNoderedInstance", "[" + tokenUser.username + "] GetNoderedInstance: found NO Namespaced Pods ???");
            }
            return results;
        }
        catch (error) {
            if (error.response && error.response.body && error.response.body.message) {
                Logger_1.Logger.instanse.error("kubedriver", "GetNoderedInstance", new Error(error.response.body.message));
                error.message = error.response.body.message;
            }
            else if (error.response && error.response.body) {
                Logger_1.Logger.instanse.error("kubedriver", "GetNoderedInstance", new Error(error.response.body));
                error.message = error.response.body;
            }
            else {
                error.message = error.message ? error.message : error;
            }
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async RestartNoderedInstance(jwt, tuser, _id, name, parent) {
        const namespace = Config_1.Config.namespace;
        const list = await KubeUtil_1.KubeUtil.instance().CoreV1Api.listNamespacedPod(namespace);
        for (let i = 0; i < list.body.items.length; i++) {
            const item = list.body.items[i];
            if (item.metadata.labels.app === name) {
                let image = "unknown";
                try {
                    image = item.spec.containers[0].image;
                }
                catch (error) {
                }
                try {
                    await KubeUtil_1.KubeUtil.instance().CoreV1Api.deleteNamespacedPod(item.metadata.name, namespace);
                    await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(tuser), true, name, "restartdeployment", image, item.metadata.name, parent);
                }
                catch (error) {
                    await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(tuser), false, name, "restartdeployment", image, item.metadata.name, parent);
                }
            }
        }
    }
    async GetNoderedInstanceLog(jwt, user, _id, name, podname, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("message.DeleteNoderedPod", parent);
        try {
            var result = null;
            const namespace = Config_1.Config.namespace;
            if (!podname.startsWith(name + "-"))
                podname = "";
            const list = await KubeUtil_1.KubeUtil.instance().CoreV1Api.listNamespacedPod(namespace);
            let image = "unknown";
            if (!openflow_api_1.NoderedUtil.IsNullEmpty(podname)) {
                if (list.body.items.length > 0) {
                    for (let i = 0; i < list.body.items.length; i++) {
                        const item = list.body.items[i];
                        if (podname == item.metadata.name) {
                            if (user.HasRoleName("admins") || item.metadata.labels.app === name) {
                                Logger_1.Logger.instanse.debug("kubedriver", "GetNoderedInstanceLog", "[" + user.username + "] GetNoderedInstanceLog: " + name + " found one as " + item.metadata.name);
                                const obj = await await KubeUtil_1.KubeUtil.instance().CoreV1Api.readNamespacedPodLog(item.metadata.name, namespace, "", false);
                                result = obj.body;
                                await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(user), true, name, "readpodlog", image, item.metadata.name, span);
                            }
                        }
                    }
                }
            }
            if (openflow_api_1.NoderedUtil.IsNullEmpty(result)) {
                if (list.body.items.length > 0) {
                    for (let i = 0; i < list.body.items.length; i++) {
                        const item = list.body.items[i];
                        try {
                            image = item.spec.containers[0].image;
                        }
                        catch (error) {
                        }
                        if (!openflow_api_1.NoderedUtil.IsNullEmpty(name) && item.metadata.name == name && user.HasRoleName("admins")) {
                            Logger_1.Logger.instanse.debug("kubedriver", "GetNoderedInstanceLog", "[" + user.username + "] GetNoderedInstanceLog: " + name + " found one as " + item.metadata.name);
                            const obj = await await KubeUtil_1.KubeUtil.instance().CoreV1Api.readNamespacedPodLog(item.metadata.name, namespace, "", false);
                            result = obj.body;
                            await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(user), true, name, "readpodlog", image, item.metadata.name, span);
                        }
                        else if (item.metadata.labels.app === name) {
                            Logger_1.Logger.instanse.debug("kubedriver", "GetNoderedInstanceLog", "[" + user.username + "] GetNoderedInstanceLog: " + name + " found one as " + item.metadata.name);
                            const obj = await await KubeUtil_1.KubeUtil.instance().CoreV1Api.readNamespacedPodLog(item.metadata.name, namespace, "", false);
                            result = obj.body;
                            await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(user), true, name, "readpodlog", image, item.metadata.name, span);
                        }
                    }
                }
            }
            if (openflow_api_1.NoderedUtil.IsNullUndefinded(result)) {
                await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(user), false, name, "readpodlog", image, null, span);
            }
            return result;
        }
        catch (error) {
            if (error.response && error.response.body && error.response.body.message) {
                Logger_1.Logger.instanse.error("kubedriver", "GetNoderedInstanceLog", new Error(error.response.body.message));
                error.message = error.response.body.message;
            }
            else if (error.response && error.response.body) {
                Logger_1.Logger.instanse.error("kubedriver", "GetNoderedInstanceLog", new Error(error.response.body));
                error.message = error.response.body;
            }
            else {
                error.message = error.message ? error.message : error;
            }
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async DeleteNoderedInstance(jwt, tokenUser, _id, name, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("message.DeleteNoderedInstance", parent);
        try {
            const namespace = Config_1.Config.namespace;
            let nodered_domain_schema = Config_1.Config.nodered_domain_schema;
            if (openflow_api_1.NoderedUtil.IsNullEmpty(nodered_domain_schema)) {
                nodered_domain_schema = "$nodered_id$." + Config_1.Config.domain;
            }
            const hostname = nodered_domain_schema.replace("$nodered_id$", name);
            const deployment = await KubeUtil_1.KubeUtil.instance().GetDeployment(namespace, name);
            if (deployment != null) {
                let image = "unknown";
                try {
                    image = deployment.spec.template.spec.containers[0].image;
                }
                catch (error) {
                }
                try {
                    await KubeUtil_1.KubeUtil.instance().AppsV1Api.deleteNamespacedDeployment(name, namespace);
                    await Audit_1.Audit.NoderedAction(tokenUser, true, name, "deletedeployment", image, null, span);
                }
                catch (error) {
                    await Audit_1.Audit.NoderedAction(tokenUser, false, name, "deletedeployment", image, null, span);
                    throw error;
                }
            }
            else {
                Logger_1.Logger.instanse.warn("kubedriver", "DeleteNoderedInstance", "_DeleteNoderedInstance: Did not find deployment for " + name + " in namespace " + namespace);
            }
            let servicename = name;
            var test = /[a-z]([-a-z0-9]*[a-z0-9])?/.exec(servicename);
            if (test == null || test.index != 0) {
                servicename = "nr" + name + "svc";
            }
            const service = await KubeUtil_1.KubeUtil.instance().GetService(namespace, servicename);
            if (service != null) {
                await KubeUtil_1.KubeUtil.instance().CoreV1Api.deleteNamespacedService(servicename, namespace);
            }
            else {
                Logger_1.Logger.instanse.warn("kubedriver", "DeleteNoderedInstance", "_DeleteNoderedInstance: Did not find service for " + name + " in namespace " + namespace);
            }
            const ingress = await KubeUtil_1.KubeUtil.instance().GetIngressV1(namespace, "useringress");
            if (ingress !== null) {
                let updated = false;
                for (let i = ingress.spec.rules.length - 1; i >= 0; i--) {
                    if (ingress.spec.rules[i].host == hostname) {
                        ingress.spec.rules.splice(i, 1);
                        updated = true;
                    }
                }
                if (updated) {
                    delete ingress.metadata.creationTimestamp;
                    await KubeUtil_1.KubeUtil.instance().NetworkingV1Api.replaceNamespacedIngress("useringress", namespace, ingress);
                }
                else {
                    Logger_1.Logger.instanse.warn("kubedriver", "DeleteNoderedInstance", "_DeleteNoderedInstance: Did not find ingress entry for " + name + " in namespace " + namespace);
                }
            }
            else {
                throw new Error("failed locating useringress");
            }
        }
        catch (error) {
            if (error.response && error.response.body && error.response.body.message) {
                Logger_1.Logger.instanse.error("kubedriver", "DeleteNoderedInstance", new Error(error.response.body.message));
                error.message = error.response.body.message;
            }
            else if (error.response && error.response.body) {
                Logger_1.Logger.instanse.error("kubedriver", "DeleteNoderedInstance", new Error(error.response.body));
                error.message = error.response.body;
            }
            else {
                error.message = error.message ? error.message : error;
            }
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async DeleteNoderedPod(jwt, user, _id, name, podname, parent) {
        const span = Logger_1.Logger.otel.startSubSpan("message.DeleteNoderedPod", parent);
        try {
            if (openflow_api_1.NoderedUtil.IsNullEmpty(podname))
                podname = name;
            const namespace = Config_1.Config.namespace;
            const list = await KubeUtil_1.KubeUtil.instance().CoreV1Api.listNamespacedPod(namespace);
            let image = "unknown";
            if (list.body.items.length > 0) {
                for (let i = 0; i < list.body.items.length; i++) {
                    const item = list.body.items[i];
                    if (item.metadata.name == podname) {
                        try {
                            image = item.spec.containers[0].image;
                        }
                        catch (error) {
                        }
                        let name = "unknown";
                        try {
                            name = item.metadata.labels.name;
                        }
                        catch (error) {
                        }
                        try {
                            await KubeUtil_1.KubeUtil.instance().CoreV1Api.deleteNamespacedPod(item.metadata.name, namespace);
                            await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(user), true, name, "deletepod", image, podname, span);
                        }
                        catch (error) {
                            await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(user), false, name, "deletepod", image, podname, span);
                            throw error;
                        }
                    }
                }
            }
            else {
                Logger_1.Logger.instanse.warn("kubedriver", "DeleteNoderedPod", "[" + user.username + "] DeleteNoderedPod: found NO Namespaced Pods ???");
                await Audit_1.Audit.NoderedAction(openflow_api_1.TokenUser.From(user), false, null, "deletepod", image, podname, span);
            }
        }
        catch (error) {
            if (error.response && error.response.body && error.response.body.message) {
                Logger_1.Logger.instanse.error("kubedriver", "DeleteNoderedPod", new Error(error.response.body.message));
                error.message = error.response.body.message;
            }
            else if (error.response && error.response.body) {
                Logger_1.Logger.instanse.error("kubedriver", "DeleteNoderedPod", new Error(error.response.body));
                error.message = error.response.body;
            }
            else {
                error.message = error.message ? error.message : error;
            }
            span === null || span === void 0 ? void 0 : span.recordException(error);
            throw error;
        }
        finally {
            Logger_1.Logger.otel.endSpan(span);
        }
    }
    async NodeLabels(parent) {
        if (Config_1.Config.nodered_allow_nodeselector) {
            const list = await KubeUtil_1.KubeUtil.instance().CoreV1Api.listNode();
            const result = {};
            if (list != null) {
                list.body.items.forEach(node => {
                    if (node.metadata && node.metadata.labels) {
                        const keys = Object.keys(node.metadata.labels);
                        keys.forEach(key => {
                            let value = node.metadata.labels[key];
                            if (result[key] == null)
                                result[key] = [];
                            if (result[key].indexOf(value) == -1)
                                result[key].push(value);
                        });
                    }
                });
            }
            return result;
        }
        return null;
    }
}
exports.kubedriver = kubedriver;
//# sourceMappingURL=kubedriver.js.map