UNPKG

@grucloud/provider-azure

Version:
453 lines (432 loc) 11.1 kB
const assert = require("assert"); const { pipe, map, tap, flatMap, filter, not, eq, get, and, assign, omit, pick, reduce, fork, switchCase, any, } = require("rubico"); const { pluck, includes, unless, when, defaultsDeep, callProp, find, values, size, last, append, isEmpty, identity, } = require("rubico/x"); const { compare, omitIfEmpty, replaceWithName, } = require("@grucloud/core/Common"); const { deepPick } = require("@grucloud/core/utils/deepPick"); const { deepDefaults } = require("@grucloud/core/utils/deepDefault"); const AppSpec = require("./resources/AppSpec"); const AuthorizationSpec = require("./resources/AuthorizationSpec"); const ContainerServiceSpec = require("./resources/ContainerServiceSpec"); const ComputeSpec = require("./resources/ComputeSpec"); const DBForPortgreSQLSpec = require("./resources/DBForPostgreSQLSpec"); const DocumentDBSpec = require("./resources/DocumentDBSpec"); const KeyVaultSpec = require("./resources/KeyVaultSpec"); const NetworkSpec = require("./resources/NetworkSpec"); const OperationalInsightsSpec = require("./resources/OperationalInsightsSpec"); const ResourceManagementSpec = require("./resources/ResourcesSpec"); const StorageSpec = require("./resources/StorageSpec"); const WebSpec = require("./resources/WebSpec"); const AzTag = require("./AzTag"); const Schema = require("./schema/AzureSchema.json"); const { AzClient } = require("./AzClient"); const { isSubstituable } = require("./AzureCommon"); const createSpecsOveride = (config) => pipe([ () => [ AppSpec, AuthorizationSpec, ComputeSpec, ContainerServiceSpec, DBForPortgreSQLSpec, DocumentDBSpec, KeyVaultSpec, NetworkSpec, OperationalInsightsSpec, ResourceManagementSpec, StorageSpec, WebSpec, ], flatMap(callProp("fnSpecs", { config })), tap((params) => { assert(true); }), ])(); exports.createSpecsOveride = createSpecsOveride; const removeBracket = callProp("replace", "[]", ""); const hasBracket = includes("[]"); const assignDeep = ({ providerConfig, lives, groupType, keys: [key, ...otherKey], }) => pipe([ tap((params) => { assert(key); assert(lives); }), when( get(removeBracket(key)), assign({ [removeBracket(key)]: pipe([ get(removeBracket(key)), switchCase([ () => isEmpty(otherKey), pipe([ replaceWithName({ groupType, path: "id", providerConfig, lives, }), ]), pipe([ switchCase([ () => hasBracket(key), map((live) => assignDeep({ providerConfig, lives, groupType, keys: otherKey, })(live) ), (live) => assignDeep({ providerConfig, lives, groupType, keys: otherKey, })(live), ]), ]), ]), ]), }) ), ]); const filterLiveOneDependency = ({ live, providerConfig, lives }) => ({ type, group, pathId = "" }) => pipe([ tap((params) => { assert(lives); assert(type); assert(group); }), () => pathId, switchCase([ isEmpty, () => live, pipe([ callProp("split", "."), (keys) => pipe([ () => live, assignDeep({ providerConfig, lives, groupType: `${group}::${type}`, keys, }), ])(), ]), ]), ])(); const filterLiveDependencyArray = ({ dependencies, providerConfig, lives }) => (live) => pipe([ () => dependencies, filter(get("list")), tap((params) => { assert(live); }), reduce( (acc, value) => defaultsDeep(acc)( filterLiveOneDependency({ providerConfig, lives, live: acc })(value) ), live ), ])(); const buildDefaultSpec = fork({ isDefault: () => () => eq(get("name"), "default"), managedByOther: () => () => eq(get("name"), "default"), ignoreResource: () => () => pipe([get("isDefault")]), findName: ({ methods, dependencies }) => ({ lives }) => (live) => pipe([ tap((params) => { assert(methods); assert(dependencies); }), () => live, fork({ path: pipe([() => methods, get("get.path"), callProp("split", "/")]), id: pipe([get("id"), callProp("split", "/")]), lives: () => lives, }), ({ path, id }) => pipe([ () => path, reduce( (acc, value, index) => pipe([ () => acc, when( and([ () => isSubstituable(value), not(eq(value, "{subscriptionId}")), not(eq(value, "{scope}")), ]), pipe([ () => id[index + size(id) - size(path)], tap((depName) => { assert(depName, `path ${path} id:${id} `); }), when( pipe([ () => ["resourceGroup"], any((type) => pipe([() => value, includes(type)])()), ]), callProp("toLowerCase") ), (depName) => [...acc, depName], ]) ), ])(), [] ), ])(), callProp("join", "::"), tap((name) => { assert(name, "missing name"); }), ])(), inferName: ({ dependencies }) => ({ dependenciesSpec }) => ({ name }) => pipe([ tap(() => { assert(dependencies); assert(dependenciesSpec); }), () => dependencies, map.entries(([key, dep]) => [key, { varName: key, ...dep }]), filter(get("parent")), values, last, switchCase([ isEmpty, () => "", ({ varName }) => pipe([ () => dependenciesSpec, get(varName), tap((name) => { assert(name); }), ])(), ]), unless( () => isEmpty(name), pipe([unless(isEmpty, append("::")), append(name)]) ), tap((params) => { assert(true); }), ])(), Client: ({ dependencies }) => ({ spec, config, lives }) => AzClient({ spec, dependencies, config, lives, }), filterLive: ({ pickPropertiesCreate = [], dependencies }) => ({ providerConfig, lives }) => //TODO pipe([ tap((params) => { assert(lives); assert(pickPropertiesCreate); assert(providerConfig); assert(dependencies); }), deepPick([ "name", "kind", ...pickPropertiesCreate, ...pipe([ () => dependencies, values, filter(get("list")), pluck("pathId"), filter(not(isEmpty)), ])(), ]), omit([ "properties.provisioningState", "etag", "type", "identity.userAssignedIdentities", ]), filterLiveDependencyArray({ dependencies, providerConfig, lives }), ]), compare: ({ pickPropertiesCreate = [], omitProperties = [], omitPropertiesExtra = [], propertiesDefaultArray, }) => compare({ filterTarget: (input) => pipe([ tap((params) => { assert(input); }), ]), filterLive: ({ live, config, filterLiveExtra = () => identity }) => pipe([ tap((params) => { assert(true); }), filterLiveExtra({ live, providerConfig: config }), tap((params) => { assert(true); }), ]), filterAll: () => pipe([ tap((params) => { assert(pickPropertiesCreate); }), deepPick(pickPropertiesCreate), tap((params) => { assert(true); }), deepDefaults(propertiesDefaultArray), tap((params) => { assert(true); }), omit(omitProperties), omit(omitPropertiesExtra), omit([ "type", //TODO keep the name and add inferName "name", "properties.provisioningState", "etag", "location", // feed 'uksouth' in, get 'UK South' out. "identity", //TODO ]), omitIfEmpty(["properties"]), tap((params) => { assert(true); }), ]), }), isOurMinion: () => AzTag.isOurMinion, }); const addDefaultSpecs = pipe([ tap((params) => { assert(true); }), map((spec) => ({ ...buildDefaultSpec(spec), ...spec })), tap((params) => { assert(true); }), ]); const findByGroupAndType = ({ group, type }) => pipe([ tap((params) => { assert(type); assert(group); }), find(and([eq(get("group"), group), eq(get("type"), type)])), ]); exports.findByGroupAndType = findByGroupAndType; const mergeSpec = ({ specsGen, specsOveride }) => pipe([ tap((params) => { assert(Array.isArray(specsGen)); assert(Array.isArray(specsOveride)); }), () => specsOveride, map((overideSpec) => pipe([ () => specsGen, findByGroupAndType(overideSpec), (found) => ({ ...found, ...overideSpec }), tap((params) => { assert(true); }), ])() ), tap((params) => { assert(true); }), ])(); exports.mergeSpec = mergeSpec; exports.fnSpecs = (config) => pipe([ assign({ specsOveride: () => createSpecsOveride(config), specsGen: pipe([() => Schema]), }), assign({ specsOveride: mergeSpec, }), assign({ specsGen: ({ specsGen, specsOveride }) => pipe([ () => specsGen, filter( not((spec) => pipe([() => specsOveride, findByGroupAndType(spec)])() ) ), ])(), }), ({ specsGen, specsOveride }) => [...specsGen, ...specsOveride], map( assign({ groupType: pipe([({ group, type }) => `${group}::${type}`]) }) ), callProp("sort", (a, b) => a.groupType.localeCompare(b.groupType)), addDefaultSpecs, tap((params) => { assert(true); }), ])();