@sap/cds-dk 8.7.3 → 8.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -1
- package/bin/bind.js +7 -8
- package/bin/cds.js +2 -4
- package/bin/compile/index.js +1 -0
- package/bin/deploy/index.js +10 -5
- package/bin/watch.js +48 -7
- package/lib/bind/{cfKeyProvider.js → cf.js} +43 -53
- package/lib/bind/k8s.js +138 -0
- package/lib/bind/plugin.js +48 -0
- package/lib/bind/shared.js +267 -0
- package/lib/build/buildTaskEngine.js +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +0 -2
- package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +1 -3
- package/lib/build/plugins/helm/files/subcharts/web-application/templates/service-binding.yaml +3 -0
- package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +3 -0
- package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +2 -1
- package/lib/build/util.js +1 -1
- package/lib/compile/to-mermaid.js +1 -2
- package/lib/deploy/to-hana/hana.js +1 -1
- package/lib/deploy/to-hana/mtaUtil.js +0 -13
- package/lib/env/schemas/cds-rc.js +17 -30
- package/lib/import/common.js +20 -10
- package/lib/init/constants.js +1 -1
- package/lib/init/merge.js +41 -32
- package/lib/init/projectReader.js +15 -7
- package/lib/init/registries/mta.js +7 -1
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/files/xs-app.json.hbs +0 -11
- package/lib/init/template/cloud-logging/files/package.json.hbs +12 -1
- package/lib/init/template/cloud-logging/files/values.yaml.hbs +0 -2
- package/lib/init/template/cloud-logging/index.js +8 -15
- package/lib/init/template/destination/files/values.yaml +4 -4
- package/lib/init/template/destination/index.js +1 -1
- package/lib/init/template/html5-repo/files/app-package.json.hbs +0 -2
- package/lib/init/template/html5-repo/files/containerize.yaml.hbs +25 -0
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +1 -2
- package/lib/init/template/html5-repo/files/package.json.hbs +1 -1
- package/lib/init/template/html5-repo/files/ui-resources/package.json.hbs +11 -0
- package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +4 -7
- package/lib/init/template/html5-repo/files/values.yaml.hbs +6 -4
- package/lib/init/template/html5-repo/index.js +22 -10
- package/lib/init/template/http/index.js +1 -1
- package/lib/init/template/lint/index.js +7 -1
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +0 -2
- package/lib/init/template/multitenancy/index.js +1 -1
- package/lib/init/template/portal/files/mta.yaml.hbs +9 -0
- package/lib/init/template/portal/index.js +3 -1
- package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +119 -119
- package/lib/init/template/sample/files/app/browse/webapp/manifest.json +1 -1
- package/lib/init/template/telemetry/index.js +0 -13
- package/lib/init/template/typer/files/package.json +3 -0
- package/lib/init/template/workzone-standard/files/cdm.json.hbs +97 -0
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +23 -0
- package/lib/init/template/workzone-standard/index.js +70 -39
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +2 -2
- package/lib/init/template/xsuaa/files/values.yaml.hbs +0 -2
- package/lib/init/template/xsuaa/index.js +22 -10
- package/lib/lint/io.js +8 -4
- package/lib/mtx/util/cf.js +1 -2
- package/lib/util/cf.js +104 -84
- package/lib/util/command.js +1 -2
- package/lib/util/git.js +1 -1
- package/npm-shrinkwrap.json +53 -45
- package/package.json +1 -1
- package/bin/deploy/to-cf.js +0 -0
- package/bin/deploy/via-mta.js +0 -0
- package/lib/bind/KubernetesApiAccessor.js +0 -81
- package/lib/bind/bindingManager.js +0 -89
- package/lib/bind/bindingResolver.js +0 -54
- package/lib/bind/bindingUtil.js +0 -129
- package/lib/bind/index.js +0 -127
- package/lib/bind/kubernetesCredentialsProvider.js +0 -84
- package/lib/bind/userCdsrcJsonStorageProvider.js +0 -92
- package/lib/init/template/destination/files/package.sidecar.json +0 -7
- package/lib/init/template/html5-repo/files/package.sidecar.json +0 -7
- package/lib/init/template/telemetry/files/package.json.hbs +0 -18
package/lib/bind/index.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
const cds = require('../cds');
|
|
2
|
-
|
|
3
|
-
const BindingResolver = require('./bindingResolver');
|
|
4
|
-
const { determineKinds, getRequiresNameFromKind, checkIsJavaProject, platformText, bindingText, logger } = require('./bindingUtil');
|
|
5
|
-
const { bold } = require('../util/term');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
module.exports = { bind, storeBindings, parseProfile, mergeCredentials }
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Executes cds build in the directory defined by cds.root.
|
|
12
|
-
*
|
|
13
|
-
* @param {object} options - command options as defined by build command.
|
|
14
|
-
*/
|
|
15
|
-
async function bind(options) {
|
|
16
|
-
let on;
|
|
17
|
-
switch (options.on) {
|
|
18
|
-
case 'k8s':
|
|
19
|
-
case 'kubernetes':
|
|
20
|
-
on = 'k8s';
|
|
21
|
-
break;
|
|
22
|
-
case undefined:
|
|
23
|
-
case null:
|
|
24
|
-
case 'cf':
|
|
25
|
-
case 'cloudfoundry':
|
|
26
|
-
on = 'cf';
|
|
27
|
-
break;
|
|
28
|
-
default:
|
|
29
|
-
throw `Invalid value '${options.on}' for option --on.`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const onText = { 'cf': 'Cloud Foundry', 'k8s': 'Kubernetes' }[on];
|
|
33
|
-
if (!options['to-app-services']) logger.log(`Retrieving data from ${bold(onText)}...`);
|
|
34
|
-
|
|
35
|
-
// run in parallel
|
|
36
|
-
const targets = options.to.split(/,/g);
|
|
37
|
-
const resolvedServices = await Promise.all(targets.map(async target => {
|
|
38
|
-
let binding;
|
|
39
|
-
if (on === 'k8s') {
|
|
40
|
-
binding = { type: on, name: target };
|
|
41
|
-
} else if (on === 'cf') {
|
|
42
|
-
const [instance, key] = target.split(/:/);
|
|
43
|
-
binding = { type: on, instance, key };
|
|
44
|
-
} else {
|
|
45
|
-
throw new Error('Internal Error');
|
|
46
|
-
}
|
|
47
|
-
const resolvedService = await BindingResolver.resolveBinding(undefined, binding);
|
|
48
|
-
resolvedService._target = target;
|
|
49
|
-
delete resolvedService.credentials;
|
|
50
|
-
resolvedService.binding.resolved = false;
|
|
51
|
-
return resolvedService;
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
if (options.kind) {
|
|
55
|
-
resolvedServices.forEach(service => service.kind = options.kind);
|
|
56
|
-
} else {
|
|
57
|
-
determineKinds(resolvedServices);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
for (const resolvedService of resolvedServices) {
|
|
61
|
-
if (options.serviceArg) {
|
|
62
|
-
resolvedService.name = options.serviceArg;
|
|
63
|
-
} else if (resolvedService.kind) {
|
|
64
|
-
resolvedService.name = getRequiresNameFromKind(resolvedService.binding.instance, resolvedService.kind);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let { kind, name, binding } = resolvedService;
|
|
68
|
-
name = name ?? `custom-service:${binding.instance || binding.secret}`
|
|
69
|
-
resolvedService.name = resolvedService.name ?? name
|
|
70
|
-
const kindText = kind ? ` with kind ${bold(kind)}` : ''
|
|
71
|
-
const nameText = bold(name)
|
|
72
|
-
|
|
73
|
-
logger.log(`Binding ${nameText} to ${platformText(binding)} ${bindingText(binding)}${kindText}`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return resolvedServices;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function storeBindings(resolvedServices, options) {
|
|
80
|
-
// prepare for different providers
|
|
81
|
-
const userCdsrcJsonStorageProvider = require('./userCdsrcJsonStorageProvider');
|
|
82
|
-
|
|
83
|
-
await userCdsrcJsonStorageProvider.storeServices(resolvedServices, {
|
|
84
|
-
...options
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
const isJavaProject = await checkIsJavaProject(cds.root);
|
|
88
|
-
if (!cds.cli.options['to-app-services']) {
|
|
89
|
-
logger.log(`\nTo run with cloud bindings use ${bold(runCmd(options.for, isJavaProject))}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function runCmd(profile, isJavaProject) {
|
|
94
|
-
profile = parseProfile(profile);
|
|
95
|
-
if (isJavaProject) {
|
|
96
|
-
const p = profile === 'hybrid' ? '' : ` --profile ${profile}`;
|
|
97
|
-
return `cds bind --exec${p} mvn spring-boot:run`;
|
|
98
|
-
} else {
|
|
99
|
-
const p = profile === 'development' ? '' : ` --profile ${profile}`;
|
|
100
|
-
return `cds watch${p}`;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function parseProfile(profile) {
|
|
105
|
-
if (!profile) return 'hybrid';
|
|
106
|
-
else if (profile === '-') return 'development';
|
|
107
|
-
else return profile;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function mergeCredentials(credentials, customCredentials) {
|
|
111
|
-
if (!customCredentials) return credentials;
|
|
112
|
-
|
|
113
|
-
for (const key in customCredentials) {
|
|
114
|
-
if (typeof customCredentials[key] === 'object') {
|
|
115
|
-
if (credentials[key] && typeof credentials[key] !== 'object') {
|
|
116
|
-
throw `Cannot merge credentials: '${key}' is not an object`;
|
|
117
|
-
}
|
|
118
|
-
if (!credentials[key]) {
|
|
119
|
-
credentials[key] = {};
|
|
120
|
-
}
|
|
121
|
-
credentials[key] = mergeCredentials(credentials[key], customCredentials[key]);
|
|
122
|
-
} else {
|
|
123
|
-
credentials[key] = customCredentials[key];
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return credentials;
|
|
127
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
const KubernetesApiAccessor = require('./KubernetesApiAccessor');
|
|
2
|
-
const { mergeCredentials } = require('./index');
|
|
3
|
-
|
|
4
|
-
class KubernetesCredentialsProvider {
|
|
5
|
-
async init() {
|
|
6
|
-
this.api = new KubernetesApiAccessor();
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async resolve(name, binding) {
|
|
10
|
-
if (!this.initPromise) {
|
|
11
|
-
this.initPromise = this.init();
|
|
12
|
-
}
|
|
13
|
-
await this.initPromise;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const { context, namespace, cluster } = await this.api.context({ cluster: binding.cluster, namespace: binding.namespace });
|
|
17
|
-
let { name: bindingName, secret, credentials: customCredentials } = binding;
|
|
18
|
-
|
|
19
|
-
let instance;
|
|
20
|
-
let secretOrBindingResource = 'Secret';
|
|
21
|
-
|
|
22
|
-
if (bindingName) {
|
|
23
|
-
const bindingResource = await this.api.get({ context, namespace, kind: 'servicebindings', name: bindingName });
|
|
24
|
-
if (bindingResource === null) {
|
|
25
|
-
// Fallback to secret instead of service binding;
|
|
26
|
-
secret = bindingName;
|
|
27
|
-
bindingName = undefined;
|
|
28
|
-
secretOrBindingResource = 'Service Binding or Secret';
|
|
29
|
-
} else {
|
|
30
|
-
const { spec } = bindingResource
|
|
31
|
-
if (!spec.secretName || !spec.serviceInstanceName) {
|
|
32
|
-
throw new Error('Internal error')
|
|
33
|
-
}
|
|
34
|
-
secret = spec.secretName;
|
|
35
|
-
instance = spec.serviceInstanceName;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const secretResource = await this.api.get({ context, namespace, kind: 'secrets', name: secret });
|
|
40
|
-
if (secretResource === null) throw new Error(`${secretOrBindingResource} '${secret}' not found.`);
|
|
41
|
-
|
|
42
|
-
const serviceBinding = this._readBinding(name, secretResource);
|
|
43
|
-
const { credentials } = serviceBinding;
|
|
44
|
-
const vcap = { ...serviceBinding, credentials: undefined }
|
|
45
|
-
|
|
46
|
-
const resolvedBinding = {
|
|
47
|
-
binding: {
|
|
48
|
-
type: 'k8s',
|
|
49
|
-
name: bindingName,
|
|
50
|
-
cluster,
|
|
51
|
-
instance,
|
|
52
|
-
namespace,
|
|
53
|
-
secret: secret,
|
|
54
|
-
resolved: true,
|
|
55
|
-
vcap
|
|
56
|
-
},
|
|
57
|
-
credentials: mergeCredentials(credentials, customCredentials)
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
return resolvedBinding;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
_readBinding(name, secret) {
|
|
64
|
-
const { data } = secret;
|
|
65
|
-
const properties = {};
|
|
66
|
-
for (const name in data) {
|
|
67
|
-
const value = Buffer.from(data[name], 'base64').toString()
|
|
68
|
-
properties[name] = value;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let parseBinding
|
|
72
|
-
try {
|
|
73
|
-
// eslint-disable-next-line
|
|
74
|
-
parseBinding = require('@sap/cds/lib/env/serviceBindings').parseBinding;
|
|
75
|
-
} catch (error) {
|
|
76
|
-
//
|
|
77
|
-
}
|
|
78
|
-
if (!parseBinding) throw new Error(`Please update your @sap/cds version for Kubernetes support`)
|
|
79
|
-
|
|
80
|
-
return parseBinding('/', name, properties);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = new KubernetesCredentialsProvider();
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
const os = require('os');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
const fs = require('fs').promises;
|
|
5
|
-
const { bold } = require('../util/term');
|
|
6
|
-
const { logger } = require('./bindingUtil');
|
|
7
|
-
|
|
8
|
-
const gitUtil = require('../util/git');
|
|
9
|
-
|
|
10
|
-
const CDSRC_FILENAME = '.cdsrc-private.json';
|
|
11
|
-
|
|
12
|
-
class UserCdsrcJsonStorageProvider {
|
|
13
|
-
|
|
14
|
-
async storeServices(services, options = {}) {
|
|
15
|
-
let jsonPath = options.out || CDSRC_FILENAME;
|
|
16
|
-
|
|
17
|
-
if (jsonPath === CDSRC_FILENAME) {
|
|
18
|
-
await gitUtil.ensureFileIsGitignored(CDSRC_FILENAME);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
jsonPath = jsonPath.replace(/~/g, os.homedir());
|
|
22
|
-
if (path.extname(jsonPath) !== '.json') {
|
|
23
|
-
jsonPath = path.join(jsonPath, '.cdsrc.json');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const jsonObject = await this.readJsonSafely(jsonPath);
|
|
27
|
-
let cdsRoot;
|
|
28
|
-
if (path.basename(jsonPath) === 'package.json') {
|
|
29
|
-
jsonObject.cds = jsonObject.cds || {};
|
|
30
|
-
cdsRoot = jsonObject.cds;
|
|
31
|
-
} else {
|
|
32
|
-
cdsRoot = jsonObject;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const profileKey = `[${options.for}]`;
|
|
36
|
-
const features = cdsRoot.features && cdsRoot.features[profileKey];
|
|
37
|
-
if (features) delete features.emulate_vcap_services;
|
|
38
|
-
|
|
39
|
-
cdsRoot.requires = cdsRoot.requires || {};
|
|
40
|
-
let section;
|
|
41
|
-
section = cdsRoot.requires[profileKey] = cdsRoot.requires[profileKey] || {};
|
|
42
|
-
|
|
43
|
-
for (const service of services) {
|
|
44
|
-
const { name, kind, binding, credentials } = service;
|
|
45
|
-
const requireService = section[name] = section[name] || {};
|
|
46
|
-
// store optional custom credentials
|
|
47
|
-
binding.credentials = this._getServiceCredentials(binding, services, options);
|
|
48
|
-
|
|
49
|
-
Object.assign(requireService, { binding: { ...binding, vcap: undefined }, credentials, kind, vcap: { name } });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
await this.writeJsonFile(jsonPath, jsonObject);
|
|
53
|
-
logger.log(`Saving bindings to ${bold(jsonPath)} in profile ${bold(options.for)}`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async readJsonSafely(filePath) {
|
|
57
|
-
try {
|
|
58
|
-
return JSON.parse(await fs.readFile(filePath));
|
|
59
|
-
} catch (err) {
|
|
60
|
-
return {};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async writeJsonFile(filePath, content) {
|
|
65
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
|
66
|
-
await fs.writeFile(filePath, JSON.stringify(content, null, 2));
|
|
67
|
-
await fs.chmod(filePath, 0o600); // -rw-------
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
_getServiceCredentials(binding, services, options) {
|
|
71
|
-
const { to, 'to-app-services': app, credentials } = options;
|
|
72
|
-
if (!credentials) {
|
|
73
|
-
return
|
|
74
|
-
}
|
|
75
|
-
// toService has format <service-name>[:<key>]
|
|
76
|
-
const toServices = to ? to.split(',') : services.map(s => s.binding.instance);
|
|
77
|
-
const toService = toServices.find(toService => binding.type === 'cf' ?
|
|
78
|
-
toService === binding.instance || toService === binding.instance + ':' + binding.key :
|
|
79
|
-
toService === binding.secret);
|
|
80
|
-
if (!toService) {
|
|
81
|
-
// must never happen
|
|
82
|
-
throw new Error(`Internal error: Service ${binding.instance}:${binding.key} not found`);
|
|
83
|
-
}
|
|
84
|
-
// app based binding always requires service name as key in credentials
|
|
85
|
-
if (!app && toServices.length === 1) {
|
|
86
|
-
return credentials[toService] || credentials;
|
|
87
|
-
}
|
|
88
|
-
return credentials[toService];
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
module.exports = new UserCdsrcJsonStorageProvider();
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"dependencies": {
|
|
3
|
-
"@cap-js/telemetry": ">=0",
|
|
4
|
-
"@grpc/grpc-js": "^1",
|
|
5
|
-
"@opentelemetry/exporter-trace-otlp-grpc": "^0",
|
|
6
|
-
"@opentelemetry/exporter-metrics-otlp-grpc": "^0",
|
|
7
|
-
"@opentelemetry/host-metrics": "^0"
|
|
8
|
-
},
|
|
9
|
-
"cds": {
|
|
10
|
-
"requires": {
|
|
11
|
-
"[{{profile}}]": {
|
|
12
|
-
"telemetry": {
|
|
13
|
-
"kind": "to-cloud-logging"
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|