Skip to content

Commit d63d5cf

Browse files
committed
feat: move the CloudFoundryApp data source to its own repo
1 parent 8d15159 commit d63d5cf

File tree

10 files changed

+1178
-0
lines changed

10 files changed

+1178
-0
lines changed

src/connector.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { GraphQLConnector } from '@console/graphql-data-source-helpers';
2+
3+
export default class CloudFoundryAppConnector extends GraphQLConnector {
4+
/**
5+
* Env-specific API endpoint for Cloud Foundry.
6+
* @member {string}
7+
*/
8+
apiBaseUri = `https://api.${process.env.cfDomain}/v2`;
9+
}

src/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import schema from './schema.graphql';
2+
import resolvers from './resolvers';
3+
import Connector from './connector';
4+
import Model from './model';
5+
6+
export default {
7+
// This is used to reference the model (e.g. context.YourModel.getAll())
8+
context: 'CloudFoundryApp',
9+
model: new Model({ connector: new Connector() }),
10+
schema,
11+
resolvers,
12+
};

src/model.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
GraphQLModel,
3+
BluemixGraphQLError,
4+
} from '@console/graphql-data-source-helpers';
5+
6+
const formatEnvVars = unformattedVars => {
7+
const envVars = {};
8+
9+
unformattedVars.forEach(keyValuePair => {
10+
envVars[keyValuePair.key] = keyValuePair.value;
11+
});
12+
13+
return envVars;
14+
};
15+
16+
export default class CloudFoundryAppModel extends GraphQLModel {
17+
/**
18+
* Loads GitHub data for a given user
19+
* @param {String} username the username to load
20+
* @return {Promise} resolves with the loaded user data
21+
*/
22+
getAppByGuid(appGuid) {
23+
return this.connector
24+
.get(`/apps/${appGuid}/summary`)
25+
.catch(res => this.handleError(res));
26+
}
27+
28+
updateAppByGuid(appGuid, updates) {
29+
// Only include env vars if they are passed-in/defined to avoid overriding them.
30+
const safeUpdates =
31+
updates.environment_json !== undefined
32+
? {
33+
...updates,
34+
environment_json: formatEnvVars(updates.environment_json),
35+
}
36+
: updates;
37+
38+
return this.connector
39+
.put(`/apps/${appGuid}`, safeUpdates)
40+
.catch(res => this.handleError(res));
41+
}
42+
43+
handleError(response) {
44+
throw BluemixGraphQLError({
45+
statusCode: response.statusCode,
46+
description: response.error.description,
47+
errorCode: response.error.error_code,
48+
targetEndpoint: response.options.uri,
49+
graphqlModel: this.constructor.name,
50+
});
51+
}
52+
}

src/resolvers.js

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
import { MockList } from 'graphql-tools';
2+
import casual from 'casual';
3+
4+
const objectHasFields = (obj, fields) => {
5+
const keys = Object.keys(obj);
6+
return keys.some(field => fields.includes(field));
7+
};
8+
9+
const summaryFields = [
10+
'routes',
11+
'running_instances',
12+
'services',
13+
'available_domains',
14+
];
15+
16+
const updateFields = [
17+
'url',
18+
'created_at',
19+
'updated_at',
20+
'space_url',
21+
'stack_url',
22+
'routes_url',
23+
'events_url',
24+
'service_bindings_url',
25+
'route_mappings_url',
26+
];
27+
28+
export const cfaTypeResolver = obj => {
29+
if (objectHasFields(obj, summaryFields)) {
30+
return 'CFA_CloudFoundryAppSummary';
31+
}
32+
33+
if (objectHasFields(obj, updateFields)) {
34+
return 'CFA_CloudFoundryAppUpdate';
35+
}
36+
37+
return null;
38+
};
39+
40+
export default {
41+
// Queries (where does the data come from?)
42+
queryResolvers: {
43+
CloudFoundryApp: ({ req }, { appGuid }, context) =>
44+
new Promise((resolve, reject) => {
45+
// Add the Bluemix token to the headers.
46+
context.CloudFoundryApp.connector.addBluemixToken(req);
47+
48+
// Get the requested data and resolve the promise.
49+
context.CloudFoundryApp
50+
.getAppByGuid(appGuid)
51+
.then(resolve)
52+
.catch(reject);
53+
}),
54+
},
55+
56+
mutationResolvers: {
57+
UpdateCloudFoundryApp: ({ req }, { appGuid, updates }, context) =>
58+
new Promise((resolve, reject) => {
59+
// Add the Bluemix token to the headers.
60+
context.CloudFoundryApp.connector.addBluemixToken(req);
61+
// Get the requested data and resolve the promise.
62+
context.CloudFoundryApp
63+
.updateAppByGuid(appGuid, updates)
64+
.then(response => {
65+
resolve({
66+
...response.body.metadata,
67+
...response.body.entity,
68+
});
69+
})
70+
.catch(reject);
71+
}),
72+
},
73+
74+
// Data fields (which data from the response goes to which field?)
75+
dataResolvers: {
76+
CFA_CloudFoundryApp: {
77+
__resolveType: cfaTypeResolver,
78+
},
79+
CFA_CloudFoundryAppSummary: {
80+
appGuid: data => data.guid,
81+
environment_json: data => JSON.stringify(data.environment_json),
82+
docker_credentials_json: data =>
83+
JSON.stringify(data.docker_credentials_json),
84+
},
85+
CFA_CloudFoundryAppUpdate: {
86+
appGuid: data => data.guid,
87+
environment_json: data => JSON.stringify(data.environment_json),
88+
docker_credentials_json: data =>
89+
JSON.stringify(data.docker_credentials_json),
90+
},
91+
CFA_Route: {
92+
routerGuid: route => route.guid,
93+
},
94+
CFA_ConnectedService: {
95+
serviceGuid: connectedService => connectedService.guid,
96+
},
97+
CFA_ServicePlan: {
98+
servicePlanGuid: servicePlan => servicePlan.guid,
99+
},
100+
CFA_Domain: {
101+
domainGuid: domain => domain.guid,
102+
router_group_guid: domain => domain.router_group_guid || null,
103+
router_group_type: domain => domain.router_group_type || null,
104+
},
105+
CFA_Service: {
106+
serviceGuid: service => service.guid,
107+
},
108+
},
109+
110+
// Mock data (How can I get real-feeling fake data while working offline?)
111+
mockResolvers: {
112+
CFA_CloudFoundryAppSummary: () => ({
113+
appGuid: casual.uuid,
114+
name: casual.array_of_words(3).join('-'),
115+
production: casual.coin_flip,
116+
space_guid: casual.uuid,
117+
stack_guid: casual.uuid,
118+
buildpack: null,
119+
detected_buildpack:
120+
'SDK for Node.js(TM) (ibm-node.js-4.8.0, buildpack-v3.11-20170303-1144)',
121+
environment_json: {},
122+
memory: casual.integer(0, 1024),
123+
instances: casual.integer(0, 1024),
124+
disk_quota: casual.integer(0, 1024),
125+
version: casual.uuid,
126+
command: 'node app.js',
127+
console: casual.coin_flip,
128+
debug: null,
129+
staging_task_id: casual.uuid,
130+
package_state: 'STAGED',
131+
health_check_http_endpoint: casual.uuid,
132+
health_check_type: 'port',
133+
health_check_timeout: null,
134+
staging_failed_reason: null,
135+
staging_failed_description: null,
136+
diego: casual.coin_flip,
137+
docker_image: null,
138+
package_updated_at: casual.date(),
139+
detected_start_command: './vendor/initial_startup.rb',
140+
enable_ssh: true,
141+
ports: null,
142+
// Implementation Fields
143+
routes: () => new MockList([1, 4]),
144+
running_instances: casual.integer(0, 10),
145+
services: () => new MockList([0, 8]),
146+
available_domains: () => new MockList([1, 8]),
147+
}),
148+
149+
CFA_CloudFoundryAppUpdate: () => ({
150+
appGuid: casual.uuid,
151+
name: casual.array_of_words(3).join('-'),
152+
production: casual.coin_flip,
153+
space_guid: casual.uuid,
154+
stack_guid: casual.uuid,
155+
buildpack: null,
156+
detected_buildpack:
157+
'SDK for Node.js(TM) (ibm-node.js-4.8.0, buildpack-v3.11-20170303-1144)',
158+
environment_json: {},
159+
memory: casual.integer(0, 1024),
160+
instances: casual.integer(0, 1024),
161+
disk_quota: casual.integer(0, 1024),
162+
version: casual.uuid,
163+
command: 'node app.js',
164+
console: casual.coin_flip,
165+
debug: null,
166+
staging_task_id: casual.uuid,
167+
package_state: 'STAGED',
168+
health_check_http_endpoint: casual.uuid,
169+
health_check_type: 'port',
170+
health_check_timeout: null,
171+
staging_failed_reason: null,
172+
staging_failed_description: null,
173+
diego: casual.coin_flip,
174+
docker_image: null,
175+
package_updated_at: casual.date(),
176+
detected_start_command: './vendor/initial_startup.rb',
177+
enable_ssh: true,
178+
ports: null,
179+
// Implementation Fields
180+
url: casual.url,
181+
created_at: `${casual.date('YYYY-MM-DD')}T${casual.time('HH:mm:ss')}Z`,
182+
updated_at: `${casual.date('YYYY-MM-DD')}T${casual.time('HH:mm:ss')}Z`,
183+
space_url: casual.url,
184+
stack_url: casual.url,
185+
routes_url: casual.url,
186+
events_url: casual.url,
187+
service_bindings_url: casual.url,
188+
route_mappings_url: casual.url,
189+
}),
190+
191+
CFA_Route: () => ({
192+
routerGuid: casual.uuid,
193+
host: casual.array_of_words(3).join('-'),
194+
port: null,
195+
path: '',
196+
domain: {
197+
domainGuid: casual.uuid,
198+
name: casual.array_of_words(3).join('-'),
199+
},
200+
}),
201+
202+
CFA_ConnectedService: () => ({
203+
serviceGuid: casual.uuid,
204+
name: casual.array_of_words(3).join('-'),
205+
bound_app_count: casual.integer(0, 10),
206+
last_operation: {
207+
type: casual.word,
208+
state: casual.word,
209+
description: casual.sentence,
210+
updated_at: casual.date(),
211+
created_at: casual.date(),
212+
},
213+
dashboard_url: casual.url,
214+
service_plan: {
215+
servicePlanGuid: casual.uuid,
216+
name: casual.array_of_words(3).join('-'),
217+
service: {
218+
serviceGuid: casual.uuid,
219+
label: casual.word,
220+
provider: null,
221+
version: null,
222+
},
223+
},
224+
}),
225+
226+
CFA_Domain: () => ({
227+
domainGuid: casual.uuid,
228+
name: casual.array_of_words(3).join('-'),
229+
router_group_guid: null,
230+
router_group_type: null,
231+
}),
232+
},
233+
};

0 commit comments

Comments
 (0)