UNPKG

@spotinst/spinnaker-deck

Version:

Spinnaker-Deck service, forked with support to Spotinst

115 lines (96 loc) 4.06 kB
import { flatMap, get, set } from 'lodash'; import { REST } from 'core/api'; import { IManagedApplicationSummary, IManagedResourceDiff, IManagedResourceEvent, IManagedResourceEventHistory, IManagedResourceEventHistoryResponse, ManagedResourceStatus, } from 'core/domain'; import { sortEnvironments } from './utils/sortEnvironments'; const KIND_NAME_MATCHER = /.*\/(.*?)@/i; const RESOURCE_DIFF_LIST_MATCHER = /^(.*)\[(.*)\]$/i; export const getKindName = (kind: string) => { const match = kind.match(KIND_NAME_MATCHER); const extractedKind = match && match[1]; return extractedKind || kind; }; export const getResourceKindForLoadBalancerType = (type: string) => { switch (type) { case 'classic': return 'classic-load-balancer'; case 'application': return 'application-load-balancer'; default: return null; } }; const transformManagedResourceDiff = (diff: IManagedResourceEventHistoryResponse[0]['delta']): IManagedResourceDiff => { if (!diff) return {}; return Object.keys(diff).reduce((transformed, key) => { const diffNode = diff[key]; const fieldKeys = flatMap<string, string>(key.split('/').filter(Boolean), (fieldKey) => { // Region keys currently come wrapped in {}, which is distracting and not useful. Let's trim those off. if (fieldKey.startsWith('{') && fieldKey.endsWith('}')) { return fieldKey.substring(1, fieldKey.length - 1); } // When items are added or removed from lists/sets, the API gives back a key like parentField[listItem]. // This trips up our slash-bashed hierarchy and means we need to extract both componnts of the list syntax, // then flatten them out into the array of nested fields const listMatch = fieldKey.match(RESOURCE_DIFF_LIST_MATCHER); if (listMatch) { const parentField = listMatch[1]; const listItem = listMatch[2]; return [parentField, listItem]; } return fieldKey; }); const path = `["${fieldKeys.join(`"]["fields"]["`)}"]`; const existingTransformedNode: IManagedResourceDiff = get(transformed, path); set(transformed, path, { ...existingTransformedNode, key, diffType: diffNode.state, actual: diffNode.current, desired: diffNode.desired, }); return transformed; }, {} as IManagedResourceDiff); }; export class ManagedReader { private static decorateResources(response: IManagedApplicationSummary) { // Individual resources don't update their status when an application is paused/resumed, // so for now let's swap to a PAUSED status and keep things simpler in downstream components. if (response.applicationPaused) { response.resources.forEach((resource) => (resource.status = ManagedResourceStatus.PAUSED)); } response.resources.forEach((resource) => (resource.isPaused = resource.status === ManagedResourceStatus.PAUSED)); return response; } public static getApplicationSummary(app: string): PromiseLike<IManagedApplicationSummary<'resources'>> { return REST('/managed/application').path(app).query({ entities: 'resources' }).get().then(this.decorateResources); } public static getEnvironmentsSummary(app: string): PromiseLike<IManagedApplicationSummary> { return REST('/managed/application') .path(app) .query({ entities: ['resources', 'artifacts', 'environments'], maxArtifactVersions: 30 }) .get() .then(this.decorateResources) .then(sortEnvironments); } public static getResourceHistory(resourceId: string): PromiseLike<IManagedResourceEventHistory> { return REST('/history') .path(resourceId) .query({ limit: 100 }) .get() .then((response: IManagedResourceEventHistoryResponse) => { response.forEach((event) => { if (event.delta) { ((event as unknown) as IManagedResourceEvent).delta = transformManagedResourceDiff(event.delta); } }); return (response as unknown) as IManagedResourceEventHistory; }); } }