@sap/cds-dk 6.4.1 → 6.5.0
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 +20 -0
- package/bin/bind.js +30 -34
- package/bin/cds.js +14 -3
- package/bin/deploy/to-sqlite.js +2 -1
- package/bin/env.js +4 -4
- package/bin/migrate.js +25 -4
- package/bin/push.js +4 -0
- package/bin/watch.js +3 -3
- package/lib/bind/KubernetesApiAccessor.js +79 -0
- package/lib/bind/{BindingManager.js → bindingManager.js} +16 -15
- package/lib/bind/bindingResolver.js +41 -68
- package/lib/bind/bindingUtil.js +93 -104
- package/lib/bind/cfKeyProvider.js +85 -74
- package/lib/bind/kubernetesCredentialsProvider.js +34 -132
- package/lib/bind/userCdsrcJsonStorageProvider.js +12 -18
- package/lib/client/params.js +2 -2
- package/lib/client/push.js +11 -6
- package/lib/client/settings_manager.js +2 -1
- package/lib/client/subscription.js +4 -1
- package/lib/import/odata/v2parser.js +32 -8
- package/lib/import/odata/v4parser.js +5 -2
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +3 -11
- package/lib/init/template/approuter/files/approuter-configmap.yaml +4 -1
- package/lib/init/template/approuter/files/approuter-mtxs-configmap.yaml +5 -1
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/files/values.yaml.hbs +1 -1
- package/lib/init/template/approuter/files/xs-app.json.hbs +2 -2
- package/lib/init/template/approuter/index.js +4 -5
- package/lib/init/template/auditlog/index.js +1 -1
- package/lib/init/template/data/index.js +1 -1
- package/lib/init/template/destinations/index.js +1 -1
- package/lib/init/template/enterprise-messaging/index.js +1 -1
- package/lib/init/template/extensibility/index.js +6 -1
- package/lib/init/template/hana/files/chart.yaml +4 -0
- package/lib/init/template/hana/files/hana.yaml +1 -0
- package/lib/init/template/hana/files/java/db/package.json +1 -1
- package/lib/init/template/hana/files/values.yaml.hbs +6 -3
- package/lib/init/template/hana/index.js +73 -21
- package/lib/init/template/helm/chart/templates/_deployment_helpers.tpl +14 -6
- package/lib/init/template/helm/chart/values.root.schema.json +10 -0
- package/lib/init/template/helm/chart/values.schema.json +11 -110
- package/lib/init/template/helm/index.js +2 -2
- package/lib/init/template/helm/subcharts/content-deployment/Chart.yaml +5 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +207 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +66 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/secret.yaml +10 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/service-account.yaml +4 -0
- package/lib/init/template/helm/subcharts/content-deployment/templates/service-binding.yaml +28 -0
- package/lib/init/template/helm/subcharts/content-deployment/values-lint.yaml +5 -0
- package/lib/init/template/helm/subcharts/content-deployment/values.md +1014 -0
- package/lib/init/template/helm/subcharts/content-deployment/values.schema.json +589 -0
- package/lib/init/template/helm/subcharts/content-deployment/values.yaml +54 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/Chart.yaml +0 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/_helpers.tpl +56 -50
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/api-rule.yaml +1 -1
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/deployment.yaml +15 -9
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/network-policy.yaml +0 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/pod-disruption-budget.yaml +2 -2
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/secret.yaml +0 -0
- package/lib/init/template/helm/subcharts/web-application/templates/service-account.yaml +6 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/service-binding.yaml +4 -3
- package/lib/init/template/helm/{subchart → subcharts/web-application}/templates/service.yaml +0 -0
- package/lib/init/template/helm/subcharts/web-application/templating.md +44 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values-lint.yaml +0 -0
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values.md +254 -200
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values.schema.json +82 -28
- package/lib/init/template/helm/{subchart → subcharts/web-application}/values.yaml +15 -5
- package/lib/init/template/html5-repo/files/chart.yaml +4 -0
- package/lib/init/template/html5-repo/files/html5-apps-deployer-configmap.yaml +14 -0
- package/lib/init/template/html5-repo/index.js +39 -7
- package/lib/init/template/kibana-logging/index.js +1 -1
- package/lib/init/template/lint/index.js +1 -1
- package/lib/init/template/multitenancy/files/saas-registry.yaml +2 -2
- package/lib/init/template/multitenancy/files/service-manager.yaml +1 -0
- package/lib/init/template/multitenancy/files/values.yaml.hbs +10 -6
- package/lib/init/template/multitenancy/index.js +21 -3
- package/lib/init/util/commandUtil.js +5 -5
- package/lib/init/util/merge.js +27 -1
- package/lib/init/util/mvnArchetypeUtil.js +1 -1
- package/lib/init/util/projectReader.js +2 -2
- package/lib/util/exec.js +3 -3
- package/lib/util/term.js +7 -7
- package/lib/watch/livereload-connect.js +187 -0
- package/lib/watch/livereload-server.js +12 -12
- package/lib/watch/node-watch.js +1 -1
- package/npm-shrinkwrap.json +532 -697
- package/package.json +1 -4
- package/lib/init/template/hana/files/hana-deployer-job.yaml +0 -49
- package/lib/init/template/html5-repo/files/_html5_deployment_helpers.tpl +0 -16
- package/lib/init/template/html5-repo/files/html5-apps-deployer-job.yaml +0 -61
- package/lib/init/util/spinner.js +0 -80
package/lib/bind/bindingUtil.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
const os = require('os');
|
|
3
2
|
const IS_WIN = os.platform() === 'win32';
|
|
4
3
|
|
|
@@ -22,128 +21,118 @@ const PreferredKinds = [
|
|
|
22
21
|
'xsuaa'
|
|
23
22
|
];
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return requiresName;
|
|
24
|
+
const PLATFORM_TYPES = {
|
|
25
|
+
'cf': 'Cloud Foundry',
|
|
26
|
+
'k8s': 'Kubernetes'
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// Build VCAP_SERVICES
|
|
39
|
-
for (const service of services) {
|
|
40
|
-
service.kindCandidates = [ ]
|
|
29
|
+
class BindingUtil {
|
|
30
|
+
static getRequiresNameFromKind(service, kind) {
|
|
31
|
+
const requiresName = KindToRequiresNameMap[kind];
|
|
32
|
+
if (!requiresName) throw new Error(`Unknown CDS service name for service "${service}". Please specify as argument for "cds bind".`)
|
|
33
|
+
return requiresName;
|
|
34
|
+
}
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Determine kind value for services based on VCAP binding
|
|
38
|
+
* information in the configuration.
|
|
39
|
+
*/
|
|
40
|
+
static determineKinds(services) {
|
|
41
|
+
const vcapServices = {}
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
// Build VCAP_SERVICES
|
|
44
|
+
for (const service of services) {
|
|
45
|
+
service.kindCandidates = []
|
|
50
46
|
|
|
51
|
-
|
|
47
|
+
const { vcap = {} } = service.binding || {};
|
|
48
|
+
let { label, type } = vcap;
|
|
49
|
+
type = type || label;
|
|
50
|
+
if (!type) continue;
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
if (!vcapServices[type]) vcapServices[type] = [];
|
|
53
|
+
vcapServices[type].push({ credentials: { dummy: 'dummy' }, ...vcap, service });
|
|
54
|
+
}
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
throwError `Please provide a service kind or update @sap/cds version to use the kind detection.`;
|
|
58
|
-
}
|
|
56
|
+
// Auto configure services based on VCAP_SERVICES
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
if (!vcapService) return;
|
|
63
|
-
if (!Object.values(requires).find( require => require !== service && require.kind == kind ))
|
|
64
|
-
vcapService.service.kindCandidates.push(kind);
|
|
65
|
-
}
|
|
58
|
+
const cds = require('../cds');
|
|
59
|
+
const env = cds.env.for('cds', process.cwd());
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
findKindFor(kind, requireService);
|
|
71
|
-
findKindFor(kind, { kind });
|
|
72
|
-
}
|
|
61
|
+
if (!env._find_credentials_for_required_service) {
|
|
62
|
+
throw new Error(`Please provide a service kind or update @sap/cds version to use the kind detection.`);
|
|
63
|
+
}
|
|
73
64
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
} if (service.kindCandidates.length === 1) {
|
|
80
|
-
service.kind = service.kindCandidates[0];
|
|
65
|
+
function findKindFor(kind, service) {
|
|
66
|
+
const vcapService = env._find_credentials_for_required_service(kind, service, vcapServices);
|
|
67
|
+
if (!vcapService) return;
|
|
68
|
+
if (!Object.values(requires).find(require => require !== service && require.kind == kind))
|
|
69
|
+
vcapService.service.kindCandidates.push(kind);
|
|
81
70
|
}
|
|
82
71
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
72
|
+
const requires = env.requires.kinds || {};
|
|
73
|
+
for (const kind of Object.keys(requires)) {
|
|
74
|
+
const requireService = requires[kind];
|
|
75
|
+
findKindFor(kind, requireService);
|
|
76
|
+
findKindFor(kind, { kind });
|
|
77
|
+
}
|
|
86
78
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
79
|
+
// Check if one "kind" per service was found
|
|
80
|
+
for (const service of services) {
|
|
81
|
+
const preferredKind = service.kindCandidates.find(kind => PreferredKinds.indexOf(kind) >= 0);
|
|
82
|
+
if (preferredKind) {
|
|
83
|
+
service.kind = preferredKind;
|
|
84
|
+
} if (service.kindCandidates.length === 1) {
|
|
85
|
+
service.kind = service.kindCandidates[0];
|
|
86
|
+
}
|
|
93
87
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const path = require('path');
|
|
97
|
-
const pomXmlPath = path.join(projectPath, 'pom.xml');
|
|
98
|
-
try {
|
|
99
|
-
await fsp.access(pomXmlPath, constants.F_OK);
|
|
100
|
-
return true;
|
|
101
|
-
} catch (err) {
|
|
102
|
-
return false;
|
|
88
|
+
delete service.kindCandidates;
|
|
89
|
+
}
|
|
103
90
|
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
*
|
|
109
|
-
* @param {string} msg
|
|
110
|
-
* @returns {never}
|
|
111
|
-
*/
|
|
112
|
-
function throwError(msg = 'Internal Error') {
|
|
113
|
-
throw new Error(msg);
|
|
114
|
-
}
|
|
115
91
|
|
|
92
|
+
static execAndExit(options, command, ...args) {
|
|
93
|
+
const { spawnSync } = require('child_process');
|
|
94
|
+
// use shell with Windows only; without output is not visible and some commands cannot be run
|
|
95
|
+
const result = spawnSync(command, args, { stdio: 'inherit', shell: IS_WIN, ...options });
|
|
96
|
+
process.exit(result.status);
|
|
97
|
+
}
|
|
116
98
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
99
|
+
static async checkIsJavaProject(projectPath) {
|
|
100
|
+
const { constants, promises: fsp } = require('fs');
|
|
101
|
+
const path = require('path');
|
|
102
|
+
const pomXmlPath = path.join(projectPath, 'pom.xml');
|
|
103
|
+
try {
|
|
104
|
+
await fsp.access(pomXmlPath, constants.F_OK);
|
|
105
|
+
return true;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
121
110
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
static platformText(binding) {
|
|
112
|
+
if (!PLATFORM_TYPES[binding.type]) throw new Error(`Unexpected binding type "${binding.type}"`);
|
|
113
|
+
return PLATFORM_TYPES[binding.type]
|
|
114
|
+
}
|
|
125
115
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
116
|
+
static bindingText(binding, highlight = t => t) {
|
|
117
|
+
switch (binding.type) {
|
|
118
|
+
case 'cf':
|
|
119
|
+
if (binding.key) {
|
|
120
|
+
return `managed service ${highlight(binding.instance + ':' + binding.key)}`
|
|
121
|
+
} else {
|
|
122
|
+
return `user provided service ${highlight(binding.instance)}`
|
|
123
|
+
}
|
|
124
|
+
case 'k8s':
|
|
125
|
+
if (binding.name) {
|
|
126
|
+
return `service binding ${highlight(binding.name)}`
|
|
127
|
+
} else {
|
|
128
|
+
return `secret ${highlight(binding.secret)}`
|
|
129
|
+
}
|
|
130
|
+
default:
|
|
131
|
+
throw new Error('Internal Error');
|
|
132
|
+
}
|
|
138
133
|
}
|
|
139
|
-
}
|
|
140
134
|
|
|
141
|
-
|
|
142
|
-
getRequiresNameFromKind,
|
|
143
|
-
determineKinds,
|
|
144
|
-
execAndExit,
|
|
145
|
-
checkIsJavaProject,
|
|
146
|
-
throwError,
|
|
147
|
-
platformText,
|
|
148
|
-
bindingText
|
|
135
|
+
static logger = { log: console.log }
|
|
149
136
|
}
|
|
137
|
+
|
|
138
|
+
module.exports = BindingUtil
|
|
@@ -3,22 +3,20 @@ const fsp = require('fs').promises;
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const util = require('util');
|
|
5
5
|
|
|
6
|
+
const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) && console.debug
|
|
7
|
+
|
|
6
8
|
const axios = require('axios');
|
|
7
9
|
const { URL } = require('url');
|
|
8
10
|
const path = require('path');
|
|
9
|
-
const
|
|
11
|
+
const { bold, highlight } = require('../util/term');
|
|
12
|
+
const { CliError } = require('../client/helper/errors');
|
|
10
13
|
|
|
11
14
|
const execAsync = util.promisify(cp.exec);
|
|
12
15
|
const IS_WIN = os.platform() === 'win32';
|
|
13
16
|
|
|
14
17
|
class CFKeyProvider {
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
this.logger = console;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
18
|
async _cfRead(...args) {
|
|
21
|
-
|
|
19
|
+
DEBUG && DEBUG(`_cfRead: cf ${args}`);
|
|
22
20
|
|
|
23
21
|
const result = await execAsync(`cf ${args}`, {
|
|
24
22
|
shell: IS_WIN,
|
|
@@ -28,20 +26,6 @@ class CFKeyProvider {
|
|
|
28
26
|
return result.stdout.toString().trim();
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
async _req(target, urlPath) {
|
|
32
|
-
const url = new URL(urlPath, target.apiEndpoint);
|
|
33
|
-
|
|
34
|
-
this.logger.debug(`_req: ${url.toString()}`);
|
|
35
|
-
|
|
36
|
-
const result = await axios.get(url.toString(), {
|
|
37
|
-
headers: {
|
|
38
|
-
authorization: target.authorization
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
return result.data;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
29
|
extract(string, pattern, errorMsg) {
|
|
46
30
|
const match = string.match(pattern);
|
|
47
31
|
if (!match || !match[1]) {
|
|
@@ -63,7 +47,7 @@ class CFKeyProvider {
|
|
|
63
47
|
}
|
|
64
48
|
}
|
|
65
49
|
} catch (err) {
|
|
66
|
-
|
|
50
|
+
DEBUG && DEBUG(`getCfTargetFromConfigFile: ${err}`);
|
|
67
51
|
}
|
|
68
52
|
}
|
|
69
53
|
|
|
@@ -82,7 +66,7 @@ class CFKeyProvider {
|
|
|
82
66
|
}
|
|
83
67
|
|
|
84
68
|
async getCfSpaceInfo() {
|
|
85
|
-
|
|
69
|
+
DEBUG && DEBUG('getting space info');
|
|
86
70
|
|
|
87
71
|
const target = await this.getCfTarget();
|
|
88
72
|
const authorization = await this.getCfAuthorization();
|
|
@@ -90,13 +74,13 @@ class CFKeyProvider {
|
|
|
90
74
|
|
|
91
75
|
|
|
92
76
|
const { org, space } = target;
|
|
93
|
-
const orgs = await
|
|
77
|
+
const orgs = await BatchRequest.req(targetWithAuth, `/v3/organizations?names=${encodeURIComponent(encodeURIComponent(org))}`);
|
|
94
78
|
if (!(orgs && orgs.resources.length === 1)) {
|
|
95
79
|
throw new Error(`CF org ${org} not found!`);
|
|
96
80
|
}
|
|
97
81
|
|
|
98
82
|
const orgGuid = orgs.resources[0].guid;
|
|
99
|
-
const spaces = await
|
|
83
|
+
const spaces = await BatchRequest.req(targetWithAuth, `/v3/spaces?names=${encodeURIComponent(encodeURIComponent(space))}&organization_guids=${encodeURIComponent(encodeURIComponent(orgGuid))}`)
|
|
100
84
|
if (!(spaces && spaces.resources.length === 1)) {
|
|
101
85
|
throw new Error(`CF space ${space} not found in org ${org}!`);
|
|
102
86
|
}
|
|
@@ -107,35 +91,30 @@ class CFKeyProvider {
|
|
|
107
91
|
}
|
|
108
92
|
|
|
109
93
|
async getCfAuthorization() {
|
|
110
|
-
|
|
94
|
+
DEBUG && DEBUG('getting authorization');
|
|
111
95
|
return this._cfRead('oauth-token');
|
|
112
96
|
}
|
|
113
97
|
|
|
114
|
-
setLogger(logger) {
|
|
115
|
-
this.logger = logger;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
98
|
async init() {
|
|
119
99
|
const target = this.target = await this.getCfSpaceInfo();
|
|
120
|
-
|
|
121
|
-
this.getOrg = BatchRequest.create({ logger, target, url: '/v3/organizations' });
|
|
100
|
+
this.getOrg = BatchRequest.create({ target, url: '/v3/organizations' });
|
|
122
101
|
this.getSpace = BatchRequest.create({
|
|
123
|
-
|
|
102
|
+
target, url: '/v3/spaces', extractors: {
|
|
124
103
|
organization_guids: resource => resource.relationships.organization.data.guid
|
|
125
104
|
}
|
|
126
105
|
});
|
|
127
106
|
this.getInstance = BatchRequest.create({
|
|
128
|
-
|
|
107
|
+
target, url: '/v3/service_instances', extractors: {
|
|
129
108
|
space_guids: resource => resource.relationships.space.data.guid
|
|
130
109
|
}
|
|
131
110
|
});
|
|
132
111
|
this.getKey = BatchRequest.create({
|
|
133
|
-
|
|
112
|
+
target, url: '/v3/service_credential_bindings', extractors: {
|
|
134
113
|
service_instance_guids: resource => resource.relationships.service_instance.data.guid
|
|
135
114
|
}
|
|
136
115
|
});
|
|
137
|
-
this.getPlans = BatchRequest.create({
|
|
138
|
-
this.getOfferings = BatchRequest.create({
|
|
116
|
+
this.getPlans = BatchRequest.create({ target, url: '/v3/service_plans' });
|
|
117
|
+
this.getOfferings = BatchRequest.create({ target, url: '/v3/service_offerings' });
|
|
139
118
|
}
|
|
140
119
|
|
|
141
120
|
async resolve(name, binding) {
|
|
@@ -143,29 +122,19 @@ class CFKeyProvider {
|
|
|
143
122
|
this.initPromise = this.init();
|
|
144
123
|
}
|
|
145
124
|
await this.initPromise;
|
|
125
|
+
this._checkApiEndpoint(name, binding)
|
|
146
126
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let { instance, key, apiEndpoint, org, space } = binding;
|
|
150
|
-
key = key || `${instance}-key`;
|
|
151
|
-
name = name || `${instance}:${key}`;
|
|
152
|
-
|
|
153
|
-
if (apiEndpoint && apiEndpoint !== target.apiEndpoint) {
|
|
154
|
-
let message = `Current Cloud Foundry API endpoint "${target.apiEndpoint}" differs from API endpoint "${apiEndpoint}" for service binding "${name}".\n`;
|
|
155
|
-
message += `Use ${term.bold(`cf login -a ${apiEndpoint}`)} to log in to the target API endpoint.`;
|
|
156
|
-
console.log(message);
|
|
157
|
-
process.exit(1);
|
|
158
|
-
}
|
|
159
|
-
|
|
127
|
+
let { instance, org, space } = binding;
|
|
160
128
|
let spaceGuid;
|
|
161
129
|
if (org && space) {
|
|
130
|
+
// org and space can be overwritten by currently logged in org and space
|
|
162
131
|
const orgObj = await this.getOrg({ names: org });
|
|
163
132
|
const spaceObj = await this.getSpace({ names: space, organization_guids: orgObj.guid });
|
|
164
133
|
spaceGuid = spaceObj.guid;
|
|
165
134
|
} else {
|
|
166
|
-
org = target.org;
|
|
167
|
-
space = target.space;
|
|
168
|
-
spaceGuid = target.spaceGuid;
|
|
135
|
+
org = this.target.org;
|
|
136
|
+
space = this.target.space;
|
|
137
|
+
spaceGuid = this.target.spaceGuid;
|
|
169
138
|
}
|
|
170
139
|
|
|
171
140
|
let instanceObj;
|
|
@@ -174,19 +143,32 @@ class CFKeyProvider {
|
|
|
174
143
|
} catch (error) {
|
|
175
144
|
throw new Error(`Service instance "${instance}" not found.`);
|
|
176
145
|
}
|
|
177
|
-
|
|
146
|
+
switch (instanceObj.type) {
|
|
147
|
+
case 'managed':
|
|
148
|
+
return this._resolveManagedService(instanceObj, instance, binding.key || `${instance}-key`, org, space);
|
|
149
|
+
case 'user-provided':
|
|
150
|
+
return this._resolveUserProvidedService(instanceObj, instance, org, space);
|
|
151
|
+
default:
|
|
152
|
+
throw new Error(`Service type ${instanceObj.type} not supported`)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async _resolveManagedService(instanceObj, instance, key, org, space) {
|
|
157
|
+
let keyObj
|
|
178
158
|
try {
|
|
179
159
|
keyObj = await this.getKey({ names: key, service_instance_guids: instanceObj.guid });
|
|
180
160
|
} catch (error) {
|
|
181
|
-
|
|
161
|
+
let message = `No service key ${highlight(key)} found for service instance ${highlight(instance)}.\n\n`;
|
|
162
|
+
message += `Use ${bold(`cf create-service-key ${instanceObj.name} ${key} [-c ...]`)} to create the required service key.`;
|
|
163
|
+
throw new CliError(message);
|
|
182
164
|
}
|
|
183
165
|
const planObj = await this.getPlans({ guids: instanceObj.relationships.service_plan.data.guid });
|
|
184
166
|
const offeringObj = await this.getOfferings({ guids: planObj.relationships.service_offering.data.guid });
|
|
185
|
-
const keyCredentialsObj = await req(this.
|
|
167
|
+
const keyCredentialsObj = await BatchRequest.req(this.target, `/v3/service_credential_bindings/${encodeURIComponent(keyObj.guid)}/details`);
|
|
186
168
|
const resolvedBinding = {
|
|
187
169
|
binding: {
|
|
188
170
|
type: "cf",
|
|
189
|
-
apiEndpoint: target.apiEndpoint,
|
|
171
|
+
apiEndpoint: this.target.apiEndpoint,
|
|
190
172
|
org: org,
|
|
191
173
|
space: space,
|
|
192
174
|
instance: instance,
|
|
@@ -203,11 +185,42 @@ class CFKeyProvider {
|
|
|
203
185
|
|
|
204
186
|
return resolvedBinding;
|
|
205
187
|
}
|
|
188
|
+
|
|
189
|
+
async _resolveUserProvidedService(instanceObj, instance, org, space) {
|
|
190
|
+
const credentialsObj = await BatchRequest.req(this.target, `/v3/service_instances/${encodeURIComponent(instanceObj.guid)}/credentials`);
|
|
191
|
+
const resolvedBinding = {
|
|
192
|
+
binding: {
|
|
193
|
+
type: "cf",
|
|
194
|
+
apiEndpoint: this.target.apiEndpoint,
|
|
195
|
+
org: org,
|
|
196
|
+
space: space,
|
|
197
|
+
instance: instance,
|
|
198
|
+
vcap: {
|
|
199
|
+
label: instanceObj.type,
|
|
200
|
+
tags: instanceObj.tags
|
|
201
|
+
},
|
|
202
|
+
resolved: true,
|
|
203
|
+
},
|
|
204
|
+
credentials: credentialsObj
|
|
205
|
+
};
|
|
206
|
+
return resolvedBinding;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
_checkApiEndpoint(name, binding) {
|
|
210
|
+
const { apiEndpoint, key, instance } = binding
|
|
211
|
+
|
|
212
|
+
// if no api endpoint is configured the currently logged in endpoint will be used
|
|
213
|
+
if (apiEndpoint && apiEndpoint !== this.target.apiEndpoint) {
|
|
214
|
+
name = `${name || instance}:${key || instance + '-key'}`
|
|
215
|
+
let message = `Current Cloud Foundry API endpoint ${highlight(this.target.apiEndpoint)} differs from API endpoint ${highlight(apiEndpoint)} for service binding ${highlight(name)}.\n\n`;
|
|
216
|
+
message += `Use ${bold(`cf login -a ${apiEndpoint}`)} to log in to the target API endpoint.`;
|
|
217
|
+
throw new CliError(message)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
206
220
|
}
|
|
207
221
|
|
|
208
222
|
class BatchRequest {
|
|
209
|
-
constructor({
|
|
210
|
-
this.logger = logger;
|
|
223
|
+
constructor({ target, url, extractors = {} }) {
|
|
211
224
|
this.target = target;
|
|
212
225
|
this.url = url;
|
|
213
226
|
this.filters = [];
|
|
@@ -247,7 +260,7 @@ class BatchRequest {
|
|
|
247
260
|
}
|
|
248
261
|
|
|
249
262
|
const params = Object.keys(filterParams).map(
|
|
250
|
-
name => `${name}=${encodeURIComponent(filterParams[name].map(
|
|
263
|
+
name => `${name}=${encodeURIComponent(filterParams[name].map(encodeURIComponent).join(','))}`
|
|
251
264
|
).join("&");
|
|
252
265
|
|
|
253
266
|
const url = this.url + (this.url.match(/\?/) ? '&' : '?') + params;
|
|
@@ -279,22 +292,20 @@ class BatchRequest {
|
|
|
279
292
|
}
|
|
280
293
|
|
|
281
294
|
async httpRequest(urlPath) {
|
|
282
|
-
return req(this.
|
|
295
|
+
return BatchRequest.req(this.target, urlPath);
|
|
283
296
|
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
async function req(logger, target, urlPath) {
|
|
287
|
-
const url = new URL(urlPath, target.apiEndpoint);
|
|
288
|
-
|
|
289
|
-
logger.debug(`_req: ${url.toString()}`);
|
|
290
297
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
});
|
|
298
|
+
static async req(target, urlPath) {
|
|
299
|
+
const url = new URL(urlPath, target.apiEndpoint);
|
|
300
|
+
DEBUG && DEBUG(`_req: ${url.toString()}`);
|
|
296
301
|
|
|
297
|
-
|
|
302
|
+
const result = await axios.get(url.toString(), {
|
|
303
|
+
headers: {
|
|
304
|
+
authorization: target.authorization
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
return result.data;
|
|
308
|
+
}
|
|
298
309
|
}
|
|
299
310
|
|
|
300
|
-
module.exports = new CFKeyProvider()
|
|
311
|
+
module.exports = new CFKeyProvider()
|