"use strict";
/*
 * Copyright © 2020 Atomist, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.deleteApplication = exports.upsertApplication = void 0;
const error_1 = require("../support/error");
const clients_1 = require("./clients");
const config_1 = require("./config");
const delete_1 = require("./delete");
const deployment_1 = require("./deployment");
const ingress_1 = require("./ingress");
const namespace_1 = require("./namespace");
const rbac_1 = require("./rbac");
const request_1 = require("./request");
const secret_1 = require("./secret");
const service_1 = require("./service");
/**
 * Create or update all the resources for an application in a
 * Kubernetes cluster.
 *
 * @param app Kubernetes application creation request
 * @param sdmFulfiller Registered name of the SDM fulfilling the deployment goal.
 * @return Array of resource specs upserted
 */
async function upsertApplication(app, sdmFulfiller) {
    let clients;
    if (app.mode === "sync") {
        clients = clients_1.makeNoOpApiClients();
    }
    else {
        let config;
        try {
            config = config_1.loadKubeConfig();
        }
        catch (e) {
            e.message = `Failed to load Kubernetes config to deploy ${app.ns}/${app.name}: ${e.message}`;
            throw e;
        }
        clients = clients_1.makeApiClients(config);
    }
    const req = Object.assign(Object.assign({}, app), { sdmFulfiller, clients });
    try {
        const k8sResources = [];
        k8sResources.push(await namespace_1.upsertNamespace(req));
        k8sResources.push(...Object.values((await rbac_1.upsertRbac(req))));
        k8sResources.push(await service_1.upsertService(req));
        k8sResources.push(...(await secret_1.upsertSecrets(req)));
        k8sResources.push(await deployment_1.upsertDeployment(req));
        k8sResources.push(await ingress_1.upsertIngress(req));
        return k8sResources.filter(r => !!r);
    }
    catch (e) {
        e.message = `Failed to upsert '${request_1.reqString(req)}': ${error_1.k8sErrMsg(e)}`;
        throw e;
    }
}
exports.upsertApplication = upsertApplication;
/**
 * Delete resources associated with an application from a Kubernetes
 * cluster.  If any resources fail to be deleted, an error is thrown.
 * If no resources associated with the application exist, it does
 * nothing successfully.
 *
 * @param req Delete application request object
 */
async function deleteApplication(del) {
    const slug = `${del.ns}/${del.name}`;
    let config;
    try {
        config = config_1.loadKubeConfig();
    }
    catch (e) {
        e.message(`Failed to load Kubernetes config to delete ${slug}: ${e.message}`);
        throw e;
    }
    const clients = clients_1.makeApiClients(config);
    const req = Object.assign(Object.assign({}, del), { clients });
    const deleted = [];
    const errs = [];
    const resourceDeleters = [
        {
            kind: "Ingress",
            namespaced: true,
            api: req.clients.net,
            lister: req.clients.net.listNamespacedIngress,
            deleter: req.clients.net.deleteNamespacedIngress,
        },
        {
            kind: "Deployment",
            namespaced: true,
            api: req.clients.apps,
            lister: req.clients.apps.listNamespacedDeployment,
            deleter: req.clients.apps.deleteNamespacedDeployment,
        },
        {
            kind: "Secret",
            namespaced: true,
            api: req.clients.core,
            lister: req.clients.core.listNamespacedSecret,
            deleter: req.clients.core.deleteNamespacedSecret,
        },
        {
            kind: "Service",
            namespaced: true,
            api: req.clients.core,
            lister: req.clients.core.listNamespacedService,
            deleter: req.clients.core.deleteNamespacedService,
        },
        {
            kind: "ClusterRoleBinding",
            namespaced: false,
            api: req.clients.rbac,
            lister: req.clients.rbac.listClusterRoleBinding,
            deleter: req.clients.rbac.deleteClusterRoleBinding,
        },
        {
            kind: "RoleBinding",
            namespaced: true,
            api: req.clients.rbac,
            lister: req.clients.rbac.listNamespacedRoleBinding,
            deleter: req.clients.rbac.deleteNamespacedRoleBinding,
        },
        {
            kind: "ClusterRole",
            namespaced: false,
            api: req.clients.rbac,
            lister: req.clients.rbac.listClusterRole,
            deleter: req.clients.rbac.deleteClusterRole,
        },
        {
            kind: "Role",
            namespaced: true,
            api: req.clients.rbac,
            lister: req.clients.rbac.listNamespacedRole,
            deleter: req.clients.rbac.deleteNamespacedRole,
        },
        {
            kind: "ServiceAccount",
            namespaced: true,
            api: req.clients.core,
            lister: req.clients.core.listNamespacedServiceAccount,
            deleter: req.clients.core.deleteNamespacedServiceAccount,
        },
    ];
    for (const rd of resourceDeleters) {
        try {
            const x = await delete_1.deleteAppResources(Object.assign(Object.assign({}, rd), { req }));
            deleted.push(...x);
        }
        catch (e) {
            e.message = `Failed to delete ${rd.kind} for ${slug}: ${error_1.k8sErrMsg(e)}`;
            errs.push(e);
        }
    }
    if (errs.length > 0) {
        throw new Error(`Failed to delete application '${request_1.reqString(req)}': ${errs.map(e => e.message).join("; ")}`);
    }
    return deleted;
}
exports.deleteApplication = deleteApplication;
//# sourceMappingURL=application.js.map