"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.labelMatch = exports.applicationLabels = exports.labelSelector = exports.matchLabels = exports.safeLabelValue = void 0;
/**
 * Remove objectionable characters from a Kubernetes label value.
 * The validation regular expression for a label value is
 * /^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$/.
 *
 * @param value The label value
 * @return A valid label value based on the input
 */
function safeLabelValue(value) {
    return value.replace(/^[^A-Za-z0-9]+/, "")
        .replace(/[^A-Za-z0-9]+$/, "")
        .replace(/[^-A-Za-z0-9_.]+/g, "_");
}
exports.safeLabelValue = safeLabelValue;
/**
 * Returns the subset of the default set of labels for that should be
 * used in a matchLabels to match a resource.
 *
 * @param req A Kubernetes request object containing at least the "name" and "workspaceId" properties
 * @return Kubernetes object metadata labels object
 */
function matchLabels(req) {
    return {
        "app.kubernetes.io/name": req.name,
        "atomist.com/workspaceId": req.workspaceId,
    };
}
exports.matchLabels = matchLabels;
/**
 * Provide label selector string suitable for passing to a Kubernetes
 * API call for the provided `req` object.
 *
 * @param req A Kubernetes request object containing at least the "name" and "workspaceId" properties
 * @return Kubernetes label selector string
 */
function labelSelector(req) {
    const matchers = matchLabels(req);
    return Object.keys(matchers).map(l => `${l}=${matchers[l]}`).join(",");
}
exports.labelSelector = labelSelector;
/**
 * Create a default set of labels for a resource.  The returned set
 * satisfy the recommendations from
 * https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
 */
function applicationLabels(req) {
    const matchers = matchLabels(req);
    const labels = Object.assign(Object.assign({}, matchers), { "app.kubernetes.io/part-of": req.name, "app.kubernetes.io/managed-by": safeLabelValue(req.sdmFulfiller) });
    if (req.component) {
        labels["app.kubernetes.io/component"] = req.component;
    }
    if (req.instance) {
        labels["app.kubernetes.io/instance"] = req.instance;
    }
    if (req.version) {
        labels["app.kubernetes.io/version"] = req.version;
    }
    return labels;
}
exports.applicationLabels = applicationLabels;
/**
 * Determine if labels match selector.  If the selector contains no
 * label selector, it is considered a match.  If the the matchLabels
 * contain no properties, it is considered matching.  If the
 * matchExpressions array is empty, it is considered matching.
 *
 * @param spec Kubernetes object spec
 * @param selector Kubernetes label selector
 * @return Return `true` if it is a match, `false` otherwise
 */
function labelMatch(spec, selector) {
    if (!selector) {
        return true;
    }
    if (!spec.metadata || !spec.metadata.labels) {
        return false;
    }
    if (selector.matchLabels) {
        for (const label of Object.keys(selector.matchLabels)) {
            if (!spec.metadata.labels.hasOwnProperty(label) || spec.metadata.labels[label] !== selector.matchLabels[label]) {
                return false;
            }
        }
    }
    if (selector.matchExpressions) {
        for (const expr of selector.matchExpressions) {
            switch (expr.operator) {
                case "Exists":
                    if (!spec.metadata.labels.hasOwnProperty(expr.key)) {
                        return false;
                    }
                    break;
                case "DoesNotExist":
                    if (spec.metadata.labels.hasOwnProperty(expr.key)) {
                        return false;
                    }
                    break;
                case "In":
                    if (!spec.metadata.labels.hasOwnProperty(expr.key) || !expr.values.includes(spec.metadata.labels[expr.key])) {
                        return false;
                    }
                    break;
                case "NotIn":
                    if (spec.metadata.labels.hasOwnProperty(expr.key) && expr.values.includes(spec.metadata.labels[expr.key])) {
                        return false;
                    }
                    break;
                default:
                    throw new Error(`Unsupported match expression operator: ${expr.operator}`);
                    break;
            }
        }
    }
    return true;
}
exports.labelMatch = labelMatch;
//# sourceMappingURL=labels.js.map