UNPKG

@axway/axway-central-cli

Version:

Manage APIs, services and publish to the Amplify Marketplace

346 lines (335 loc) 17.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.testables = exports.setupKubernetes = exports.setupIstio = exports.istioSystemNs = exports.istioPrompts = exports.installPreprocess = exports.gatewayConnectivity = exports.gatewayCertSecret = exports.defaultLogFiles = exports.createIstioOverride = exports.createIstioGatewayCert = exports.createHybridOverride = exports.completeInstall = exports.askIstioSecret = exports.askConfigType = exports.askBundleType = exports.amplifyAgentsNs = exports.amplifyAgentsCredsSecret = exports.ampcDemoNs = exports.IstioInstallMethods = exports.ConfigFiles = exports.AlsMode = void 0; var _chalk = _interopRequireDefault(require("chalk")); var _snooplogg = _interopRequireDefault(require("snooplogg")); var _bashCommands = require("../../common/bashCommands"); var _basicPrompts = require("../../common/basicPrompts"); var _Kubectl = require("../../common/Kubectl"); var _types = require("../../common/types"); var _utils = require("../../common/utils"); var _helpers = _interopRequireWildcard(require("./helpers")); var helpers = _helpers; var _inputs = require("./helpers/inputs"); var _istioTemplates = require("./helpers/templates/istioTemplates"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } // @ts-ignore const { log } = (0, _snooplogg.default)('engage: install: agents: istio:'); const amplifyAgentsNs = exports.amplifyAgentsNs = 'amplify-agents'; const gatewayCertSecret = exports.gatewayCertSecret = 'gateway-cert'; const istioSystemNs = exports.istioSystemNs = 'istio-system'; const ampcDemoNs = exports.ampcDemoNs = 'ampc-demo'; const defaultLogFiles = exports.defaultLogFiles = '/group-*_instance-*.log'; const amplifyAgentsCredsSecret = exports.amplifyAgentsCredsSecret = 'amplify-agents-credentials'; let AlsMode = exports.AlsMode = /*#__PURE__*/function (AlsMode) { AlsMode["Verbose"] = "verbose"; AlsMode["Default"] = "default"; AlsMode["Ambient"] = "ambient"; return AlsMode; }({}); // ConfigFiles - all the config file that are used in the setup const ConfigFiles = exports.ConfigFiles = { IstioOverrideFile: 'istio-override.yaml', HybridOverrideFile: 'hybrid-override.yaml' }; const istioPrompts = exports.istioPrompts = { // istio enterProtocol: 'Enter the protocol to use for the ingress gateway', enterPort: 'Enter the Kubernetes cluster port', enterIstioSecret: 'Enter the name of the secret to store the Istio gateway certificate', generateCertPrompt: 'Would you like to generate a self signed certificate, or provide your own?', enterDomainName: 'Enter the public domain name for your cluster (FQDN), if available. (leave blank to skip)', enterCertPath: 'Enter the file path to the certificate', existingIstio: 'Use existing Istio installation?', askEnvoyFilterNamespace: 'Select the namespace where you would like the ALS Envoy Filters to be applied', istioProfile: 'Select the Istio profile to use', // agents meshAgentNamespace: 'Enter the namespace to use for the Amplify Istio Agents', vsNamespaces: 'Select the namespace where the agent should discover Virtual Service resources', alsMode: 'Select Traceability Agent HTTP header publishing mode', demoService: 'Do you want to deploy the optional demo application?' }; const askBundleType = async () => { return await (0, _basicPrompts.askList)({ msg: helpers.agentMessages.selectAgentType, choices: [_types.BundleType.ALL_AGENTS, _types.BundleType.DISCOVERY, _types.BundleType.TRACEABILITY] }); }; exports.askBundleType = askBundleType; const askConfigType = async () => { return _types.AgentConfigTypes.DOCKERIZED; }; exports.askConfigType = askConfigType; const gatewayConnectivity = async installConfig => { let istioValues = new _istioTemplates.IstioValues(); console.log('\nCONNECTING A KUBERNETES CLUSTER TO AMPLIFY CENTRAL\n'); console.log(_chalk.default.gray(`The Amplify Istio Discovery Agent needs to be deployed to your Kubernetes cluster to discover APIs for publishing to Amplify Central and/or the Amplify Marketplace. The Amplify Istio Traceability Agent needs to be deployed to your Kubernetes cluster to collect transaction telemetry to send to the Amplify Central Observer and Visibility Dashboard.`)); console.log(` For more details on client prerequesites or Kubernetes preparation refer to the documentation here: https://docs.axway.com/bundle/amplify-central/page/docs/connect_manage_environ/mesh_management/build_hybrid_env/index.html `); const { error } = await _Kubectl.kubectl.isInstalled(); if (error) { throw new Error(`Kubectl is required to fill out the following prompts. It appears to be missing or misconfigured.\n${error}`); } const istioOverrides = await setupIstio(istioValues); installConfig.gatewayConfig = istioValues; // Set up the following values from installConfig to be used in setupKubernetes istioValues.istioAgentValues.alsEnabled = installConfig.switches.isTaEnabled; istioValues.istioAgentValues.discoveryEnabled = installConfig.switches.isDaEnabled; const hybridOverrides = await setupKubernetes(istioValues); hybridOverrides.envoyFilterNamespace = istioOverrides.envoyFilterNamespace; istioOverrides.alsNamespace = hybridOverrides.namespace.name; istioOverrides.enableAls = hybridOverrides.alsMode === AlsMode.Verbose; istioOverrides.enableTracing = hybridOverrides.alsEnabled; return istioValues; }; // Questions for the istio configuration exports.gatewayConnectivity = gatewayConnectivity; const askUseExistingIstio = async () => (0, _basicPrompts.askList)({ msg: istioPrompts.existingIstio, choices: _types.YesNoChoices }); const askEnvoyFilterNamespace = async namespaces => (0, _basicPrompts.askList)({ msg: istioPrompts.askEnvoyFilterNamespace, choices: namespaces.data }); const askHost = async () => await (0, _basicPrompts.askInput)({ msg: istioPrompts.enterDomainName, validate: (0, _basicPrompts.validateRegex)(_helpers.domainNameRegex, _helpers.invalidDomainName), allowEmptyInput: true }); const askProtocol = async () => (0, _basicPrompts.askList)({ msg: istioPrompts.enterProtocol, choices: [{ name: _types.Protocol.HTTP.toUpperCase(), value: _types.Protocol.HTTP }, { name: _types.Protocol.HTTPS.toUpperCase(), value: _types.Protocol.HTTPS }] }); const askPort = async protocol => await (0, _basicPrompts.askInput)({ msg: istioPrompts.enterPort, type: 'number', defaultValue: protocol === _types.Protocol.HTTP ? 8080 : 443 }); const askCertificateOption = async () => (0, _basicPrompts.askList)({ msg: istioPrompts.generateCertPrompt, choices: [{ name: 'Generate self signed certificate', value: _types.Certificate.GENERATE }, { name: 'Provide certificate', value: _types.Certificate.PROVIDE }] }); const askIstioProfile = async () => (0, _basicPrompts.askList)({ msg: istioPrompts.istioProfile, choices: _types.IstioProfileChoices }); //Setup Overrides const setupIstio = async istioValues => { let istioInstallValues = istioValues.istioInstallValues; console.log(_chalk.default.gray('If Istio is not yet installed, select No. If Istio is already running select Yes.\n')); const useExistingIstio = await askUseExistingIstio(); if (useExistingIstio === _types.YesNo.Yes) { const namespaces = await _Kubectl.kubectl.get('namespaces'); if (namespaces.error) throw new Error(namespaces.error); const filterNamespace = await askEnvoyFilterNamespace(namespaces); istioInstallValues.envoyFilterNamespace = filterNamespace; istioInstallValues.isNewInstall = false; return istioInstallValues; } istioInstallValues.profile = await askIstioProfile(); console.log(_chalk.default.gray('\nFor a Kubernetes cluster exposing HTTPS endpoints, you must own or be able to configure a certificate for the correspoinding fully qualified domain name\n')); istioInstallValues.host = (await askHost()).toLowerCase(); if (istioInstallValues.host) { istioInstallValues.protocol = await askProtocol(); istioInstallValues.port = await askPort(istioInstallValues.protocol); if (istioInstallValues.protocol === _types.Protocol.HTTPS) { istioInstallValues.certSecretName = await askIstioSecret(istioPrompts.enterIstioSecret, istioSystemNs, gatewayCertSecret); istioInstallValues.certificateOption = await askCertificateOption(); } } istioInstallValues.targetPort = istioInstallValues.protocol === _types.Protocol.HTTP ? 8080 : 8443; return istioValues.istioInstallValues; }; exports.setupIstio = setupIstio; const askIstioSecret = async (msg, namespace, defaultSecretName) => { const allSecrets = await _Kubectl.kubectl.get('secrets', `-n ${namespace}`); // No resources errors are ok. Throw an error for anything else. if (allSecrets.error && !allSecrets.error.includes('K8S secrets: No resources found')) throw Error(allSecrets.error); return (0, _inputs.askForSecretName)(msg, defaultSecretName, allSecrets.data); }; exports.askIstioSecret = askIstioSecret; const completeIstio = async istioOverrides => { if (istioOverrides.protocol === _types.Protocol.HTTPS) { if (istioOverrides.isNewInstall) { await _Kubectl.kubectl.create('ns', istioSystemNs); } await createIstioGatewayCert(istioOverrides.envoyFilterNamespace, istioOverrides); } }; // Above this line is Istio. Below is Kubernetes // Questions for the kubernetes configuration const askALSMode = async () => { return (0, _basicPrompts.askList)({ msg: istioPrompts.alsMode, choices: [{ name: AlsMode.Ambient.charAt(0).toUpperCase() + AlsMode.Ambient.slice(1), value: AlsMode.Ambient }, { name: AlsMode.Default.charAt(0).toUpperCase() + AlsMode.Default.slice(1), value: AlsMode.Default }, { name: AlsMode.Verbose.charAt(0).toUpperCase() + AlsMode.Verbose.slice(1), value: AlsMode.Verbose }], default: AlsMode.Ambient }); }; const askVsNamespacePrompt = async () => { const namespaces = await _Kubectl.kubectl.get('ns'); if (namespaces.error) throw Error(namespaces.error); return await (0, _basicPrompts.askList)({ msg: istioPrompts.vsNamespaces, choices: namespaces.data }); }; const askEnableDemoSvc = async () => { const res = (0, _basicPrompts.askList)({ msg: istioPrompts.demoService, choices: _types.YesNoChoices }); return (await res) === _types.YesNo.Yes ? true : false; }; //Setup Overrides const setupKubernetes = async istioValues => { let istioAgentValues = istioValues.istioAgentValues; console.log(_chalk.default.gray(`\nThere are several steps to prepare a Kubernetes cluster for the Amplify Istio Agents.\nThe following questions collect the namespace and secret to use for the Istio gateway.\n`)); if (istioAgentValues.alsEnabled) { console.log(_chalk.default.gray(`\nThe Istio Traceability Agent supports three modes: default (minimal required header subset), ambient (baseline headers with optional Telemetry CR emission), and verbose (capture all request/response headers).\n`)); istioAgentValues.alsMode = await askALSMode(); } if (istioAgentValues.discoveryEnabled) { const ns = await askVsNamespacePrompt(); istioAgentValues.discoveryNamespaces = [ns]; } istioAgentValues.namespace = await (0, _inputs.askNamespace)(istioPrompts.meshAgentNamespace, amplifyAgentsNs); istioAgentValues.demoSvcEnabled = await askEnableDemoSvc(); if (istioAgentValues.discoveryEnabled && istioAgentValues.demoSvcEnabled && !istioAgentValues.discoveryNamespaces.includes(ampcDemoNs)) { istioAgentValues.discoveryNamespaces.push(ampcDemoNs); } // set keySecretName istioAgentValues.keysSecretName = helpers.amplifyAgentsKeysSecret; istioAgentValues.clusterName = await (0, _helpers.askClusterName)(); return istioAgentValues; }; exports.setupKubernetes = setupKubernetes; const createIstioGatewayCert = async (namespace, istioOverrides) => { let privateKey = ''; let cert = ''; if (istioOverrides.certificateOption === _types.Certificate.GENERATE) { ({ cert, privateKey } = await (0, _bashCommands.createTlsCert)(istioOverrides.certSecretName, istioOverrides.host)); console.log(`Created ${istioOverrides.certSecretName}.crt and ${istioOverrides.certSecretName}.key in ${process.cwd()}`); } else { privateKey = await (0, _basicPrompts.askInput)({ msg: _helpers.enterPublicKeyPath }); cert = await (0, _basicPrompts.askInput)({ msg: istioPrompts.enterCertPath }); } const { data, error } = await _Kubectl.kubectl.create('secret', `-n ${namespace} tls ${istioOverrides.certSecretName} --cert=${cert} --key=${privateKey}`); if (error) throw new Error(error); console.log(`Created ${data[0]} in the ${namespace} namespace.`); }; exports.createIstioGatewayCert = createIstioGatewayCert; const createIstioOverride = overrides => { const overrideFileName = ConfigFiles.IstioOverrideFile; (0, _utils.writeTemplates)(overrideFileName, overrides, helpers.istioInstallTemplate); console.log(`\nIstio override file has been placed at ${process.cwd()}/${overrideFileName}`); if (overrides.istioInstallValues.isNewInstall) { console.log('To complete the istio installation run the following command:', _chalk.default.cyan(`\n istioctl install --set profile=${overrides.istioInstallValues.profile} -f ${overrideFileName}\n`)); } else { console.log(_chalk.default.cyan(` Please merge the generated ${overrideFileName} file with your Istio configuration to allow the Traceability Agent to function.\n`)); } }; exports.createIstioOverride = createIstioOverride; const createHybridOverride = overrides => { const overrideFileName = ConfigFiles.HybridOverrideFile; (0, _utils.writeTemplates)(overrideFileName, overrides, helpers.istioAgentsTemplate); console.log(`Istio agent override file has been placed at ${process.cwd()}/${overrideFileName}`); helpers.helmImageSecretInfo(overrides.istioAgentValues.namespace.name); let agentHelmInfo = new Set(); agentHelmInfo.add({ helmReleaseName: 'ampc-hybrid', helmChartName: 'axway/ampc-hybrid', overrideFileName: overrideFileName, imageSecretOverrides: `--set da.image.pullSecret=<image-pull-secret-name> --set als.image.pullSecret=<image-pull-secret-name>` }); helpers.helmInstallInfo('Istio', overrides.istioAgentValues.namespace.name, agentHelmInfo); }; exports.createHybridOverride = createHybridOverride; const installPreprocess = async installConfig => { // name of the service account, and if it is new or not if (!installConfig.centralConfig.ampcDosaInfo.isNew) { [installConfig.centralConfig.dosaAccount.publicKey, installConfig.centralConfig.dosaAccount.privateKey] = await helpers.askPublicAndPrivateKeysPath(); } else { console.log(_chalk.default.yellow(`The secret will be created with the same "private_key.pem" and "public_key.pem" that will be auto generated to create the Service Account, following the completion of these prompts.`)); } return installConfig; }; exports.installPreprocess = installPreprocess; const completeInstall = async installConfig => { // Contents of completeKubernetes moved here. const istioValues = installConfig.gatewayConfig; // Add final settings to IstioAgentsValues istioValues.centralConfig = installConfig.centralConfig; istioValues.traceabilityConfig = installConfig.traceabilityConfig; await completeIstio(istioValues.istioInstallValues); if (istioValues.istioAgentValues.namespace.isNew) { await helpers.createNamespace(istioValues.istioAgentValues.namespace.name); } await helpers.createSecret(istioValues.istioAgentValues.namespace.name, helpers.amplifyAgentsKeysSecret, async () => { if (installConfig.centralConfig.ampcDosaInfo.isNew) { console.log(_chalk.default.yellow(`The secret '${helpers.amplifyAgentsKeysSecret}' will be created with the same "private_key.pem" and "public_key.pem" that was auto generated to create the Service Account.`)); } await helpers.createAmplifyAgentKeysSecret(istioValues.istioAgentValues.namespace.name, helpers.amplifyAgentsKeysSecret, 'publicKey', istioValues.centralConfig.dosaAccount.publicKey, 'privateKey', istioValues.centralConfig.dosaAccount.privateKey); }); console.log('Generating the configuration file(s)...'); createIstioOverride(istioValues); createHybridOverride(istioValues); console.log('Configuration file(s) have been successfully created.\n'); console.log(_chalk.default.gray(`\nAdditional information about agent features can be found here:\n${helpers.agentsDocsUrl.ISTIO}`)); }; exports.completeInstall = completeInstall; const IstioInstallMethods = exports.IstioInstallMethods = { GetBundleType: askBundleType, GetDeploymentType: askConfigType, AskGatewayQuestions: gatewayConnectivity, InstallPreprocess: installPreprocess, FinalizeGatewayInstall: completeInstall, ConfigFiles: Object.values(ConfigFiles), GatewayDisplay: _types.GatewayTypes.ISTIO }; const testables = exports.testables = { istioPrompts, ConfigFiles, defaultLogFiles, amplifyAgentsCredsSecret };