@atomist/sdm
Version:
Atomist Software Delivery Machine SDK
126 lines • 5.42 kB
JavaScript
;
/*
* 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.hasMetadataAnnotation = exports.filterIgnoredSpecs = exports.calculateChanges = exports.changeResource = void 0;
const configuration_1 = require("@atomist/automation-client/lib/configuration");
const _ = require("lodash");
const apply_1 = require("../kubernetes/apply");
const delete_1 = require("../kubernetes/delete");
const secret_1 = require("../kubernetes/secret");
const spec_1 = require("../kubernetes/spec");
const application_1 = require("./application");
const previousSpecVersion_1 = require("./previousSpecVersion");
/**
* Delete/apply resources in change. The spec file provided by the
* change.path may contain multiple specs. The requested change is
* applied to each.
*/
async function changeResource(p, change) {
const beforeContents = await previousSpecVersion_1.previousSpecVersion(p.baseDir, change.path, change.sha);
const beforeSpecs = spec_1.parseKubernetesSpecs(beforeContents);
let specs;
if (change.change !== "delete") {
const specFile = await p.getFile(change.path);
if (!specFile) {
throw new Error(`Resource spec file '${change.path}' does not exist in project`);
}
const specContents = await specFile.getContent();
specs = spec_1.parseKubernetesSpecs(specContents);
}
const changes = calculateChanges(beforeSpecs, specs, change.change);
const syncOpts = configuration_1.configurationValue("sdm.k8s.options.sync", {});
for (const specChange of changes) {
let changer;
if (specChange.change === "delete") {
changer = delete_1.deleteSpec;
}
else {
changer = apply_1.applySpec;
}
_.set(specChange.spec, "metadata.annotations['atomist.com/sync-sha']", change.sha);
if (specChange.change !== "delete" && specChange.spec.kind === "Secret" && syncOpts.secretKey) {
specChange.spec = await secret_1.decryptSecret(specChange.spec, syncOpts.secretKey);
}
await changer(specChange.spec);
}
}
exports.changeResource = changeResource;
/**
* Inspect before and after specs to determine actions.
*
* If the action is "delete", return delete actions for all specs in
* `before` that do not have an ignore annotation for the current SDM,
* as the "delete" action implies there are no `after` specs.
*
* If the action is "apply", return apply actions for all specs in
* `after` and delete actions for all specs in `before` that are not
* in `after` that do not have an ignore annotation for the current
* SDM. If a `before` spec contains a sync ignore annotation for the
* current SDM and the `after` annotation does not, the `after` spec
* with an "apply" action is included in the returned changes. If an
* `after` spec contains a sync ignore annotation for the current SDM,
* then it is omitted from the returned changes, regardless of whether
* it appears in the `before` specs or not.
*
* @param before The specs before the change
* @param after The specs after the change
* @param change The type of change
* @return Array containing the type of change for each spec
*/
function calculateChanges(before, after, change) {
const beforeFiltered = filterIgnoredSpecs(before);
if (change === "delete") {
return beforeFiltered.map(spec => ({ change, spec }));
}
const changes = filterIgnoredSpecs(after).map(spec => ({ change, spec }));
for (const spec of beforeFiltered) {
if (!after.some(a => application_1.sameObject(a, spec))) {
changes.push({ change: "delete", spec });
}
}
return changes;
}
exports.calculateChanges = calculateChanges;
/**
* Returned array of specs with those that should be ignored filtered
* out.
*
* @param specs Array of specs to check
* @return Array of not ignored specs.
*/
function filterIgnoredSpecs(specs) {
if (!specs) {
return [];
}
return specs.filter(spec => !hasMetadataAnnotation(spec, "sync", "ignore"));
}
exports.filterIgnoredSpecs = filterIgnoredSpecs;
/**
* Check if the Kubernetes Object has an annotation that is relevant to the current SDM
* @param spec the spec to inspect
* @param annotationKey the key to validate for
* @param annotationValue the value validate for
* @returns the result of the annotation inspection
*/
function hasMetadataAnnotation(spec, annotationKey, annotationValue) {
const sdmName = configuration_1.configurationValue("name");
const nameKey = `atomist.com/sdm-pack-k8s/${annotationKey}/${sdmName}`;
const specValue = _.get(spec, `metadata.annotations['${nameKey}']`);
return !!specValue && specValue === annotationValue;
}
exports.hasMetadataAnnotation = hasMetadataAnnotation;
//# sourceMappingURL=change.js.map