@axway/axway-central-cli
Version:
Manage APIs, services and publish to the Amplify Marketplace
380 lines (369 loc) • 19.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.testables = exports.setupKubernetes = exports.setupIstio = exports.istioSystemNs = exports.istioPrompts = exports.installPreprocess = exports.getCondorHost = exports.gatewayConnectivity = exports.gatewayCertSecret = exports.defaultLogFiles = exports.createIstioOverride = exports.createIstioGatewayCert = exports.createHybridOverride = exports.createEnvResources = 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 _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
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";
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.Default.charAt(0).toUpperCase() + AlsMode.Default.slice(1),
value: AlsMode.Default
}, {
name: AlsMode.Verbose.charAt(0).toUpperCase() + AlsMode.Verbose.slice(1),
value: AlsMode.Verbose
}]
});
};
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 can log a minimal set of HTTP headers needed for transaction publishing (default) or it can capture all headers (verbose).\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.askK8sClusterName)();
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 getCondorHost = (region, env, apicDeployment) => {
var _hosts$region, _hosts$region$env;
const hosts = {
[_types.Regions.US]: {
[_types.Platforms.prod]: {
[_types.APICDeployments.US]: _types.IngestionHosts.US
},
[_types.Platforms.staging]: {
[_types.APICDeployments.USStaging]: _types.IngestionHosts.USStaging,
[_types.APICDeployments.QA]: _types.IngestionHosts.QA,
[_types.APICDeployments.TEAMS]: _types.IngestionHosts.QA
}
},
[_types.Regions.EU]: {
[_types.Platforms.prod]: {
[_types.APICDeployments.EU]: _types.IngestionHosts.EU
},
[_types.Platforms.staging]: {
[_types.APICDeployments.EUStaging]: _types.IngestionHosts.EUStaging
}
},
[_types.Regions.AP]: {
[_types.Platforms.prod]: {
[_types.APICDeployments.AP]: _types.IngestionHosts.AP
},
[_types.Platforms.staging]: {
[_types.APICDeployments.APStaging]: _types.IngestionHosts.APStaging
}
}
};
return ((_hosts$region = hosts[region]) === null || _hosts$region === void 0 ? void 0 : (_hosts$region$env = _hosts$region[env]) === null || _hosts$region$env === void 0 ? void 0 : _hosts$region$env[apicDeployment]) || _types.IngestionHosts.US;
};
exports.getCondorHost = getCondorHost;
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 createEnvResources = async (client, defs, clusterName) => {
// Create the mesh K8SCluster resource
await helpers.createByResourceType(client, defs, clusterName, 'K8SCluster', 'k8sc', {}, '');
};
exports.createEnvResources = createEnvResources;
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
};