"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.deleteAppResources = exports.deleteSpec = void 0;
const logger_1 = require("@atomist/automation-client/lib/util/logger");
const error_1 = require("../support/error");
const retry_1 = require("../support/retry");
const api_1 = require("./api");
const config_1 = require("./config");
const labels_1 = require("./labels");
const request_1 = require("./request");
const resource_1 = require("./resource");
const spec_1 = require("./spec");
/**
 * Delete a resource if it exists.  If the resource does not exist,
 * do nothing.
 *
 * @param spec Kuberenetes spec of resource to delete
 * @return DeleteResponse if object existed and was deleted, undefined if it did not exist
 */
async function deleteSpec(spec) {
    const slug = spec_1.specSlug(spec);
    let client;
    try {
        const kc = config_1.loadKubeConfig();
        client = kc.makeApiClient(api_1.K8sObjectApi);
    }
    catch (e) {
        e.message = `Failed to create Kubernetes client: ${error_1.k8sErrMsg(e)}`;
        throw e;
    }
    try {
        await client.read(spec);
    }
    catch (e) {
        logger_1.logger.debug(`Kubernetes resource ${slug} does not exist: ${error_1.k8sErrMsg(e)}`);
        return undefined;
    }
    logger_1.logger.info(`Deleting resource ${slug} using '${resource_1.logObject(spec)}'`);
    return retry_1.logRetry(() => client.delete(spec), `delete resource ${slug}`);
}
exports.deleteSpec = deleteSpec;
/**
 * Delete resources associated with application described by `arg.req`, if
 * any exists.  If no matching resources exist, do nothing.  Return
 * ann array of deleted resources, which may be empty.
 *
 * @param arg Specification of what and how to delete for what application
 * @return Array of deleted resources
 */
async function deleteAppResources(arg) {
    const slug = request_1.appName(arg.req);
    const selector = labels_1.labelSelector(arg.req);
    const toDelete = [];
    try {
        const limit = 500;
        let continu;
        do {
            let listResp;
            const args = [
                undefined,
                undefined,
                continu,
                undefined,
                selector,
                limit,
            ];
            if (arg.namespaced) {
                listResp = await arg.lister.call(arg.api, arg.req.ns, ...args);
            }
            else if (arg.namespaced === false) {
                listResp = await arg.lister.apply(arg.api, args);
            }
            toDelete.push(...listResp.body.items.map(r => {
                r.kind = r.kind || arg.kind; // list response does not include kind
                return r;
            }));
            continu = listResp.body.metadata._continue;
        } while (!!continu);
    }
    catch (e) {
        e.message = `Failed to list ${arg.kind} for ${slug}: ${error_1.k8sErrMsg(e)}`;
        throw e;
    }
    const deleted = [];
    const errs = [];
    for (const resource of toDelete) {
        const resourceSlug = arg.namespaced
            ? `${arg.kind}/${resource.metadata.namespace}/${resource.metadata.name}`
            : `${arg.kind}/${resource.metadata.name}`;
        logger_1.logger.info(`Deleting ${resourceSlug} for ${slug}`);
        try {
            const args = [
                undefined,
                undefined,
                undefined,
                undefined,
                "Background",
            ];
            if (arg.namespaced) {
                await arg.deleter.call(arg.api, resource.metadata.name, resource.metadata.namespace, ...args);
            }
            else if (arg.namespaced === false) {
                await arg.deleter.call(arg.api, resource.metadata.name, ...args);
            }
            deleted.push(resource);
        }
        catch (e) {
            e.message = `Failed to delete ${resourceSlug} for ${slug}: ${error_1.k8sErrMsg(e)}`;
            errs.push(e);
        }
    }
    if (errs.length > 0) {
        throw new Error(`Failed to delete ${arg.kind} resources for ${slug}: ${errs.map(e => e.message).join("; ")}`);
    }
    return deleted;
}
exports.deleteAppResources = deleteAppResources;
//# sourceMappingURL=delete.js.map