-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheureka.js
187 lines (155 loc) · 6.27 KB
/
eureka.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/**
* Wrapper around eureka-js-client that provides endpoints for the spring boot admin / eureka.
*/
const Eureka = require('eureka-js-client').Eureka;
const ip = require('ip');
const request = require('./lib/request-promise');
const expressIntegration = require('./lib/eureka-express');
const os = require('os');
// This is used as default logger
var log = {
debug : (s) => {console.log('DEBUG: '+s)},
info : (s) => {console.log('INFO : '+s)},
warn : (s) => {console.log('WARN : '+s)},
error : (s) => {console.log('ERROR: '+s)}
}
// Substitute config variables.
// This replaces configs like 'http://${myserver}' with the actual value
// Regular expression constructed with the help of https://regexr.com/
const substitute = (input, args) => input.replace(/\${([a-z0-9.]+)}/gi, (_, v) => { return args[v] });
const exported = (eurekaClient, parameter) => {
const getAppUrl = function(id) {
if( !eurekaClient ) throw new Error("getAppUrl is not possible. Registration was skipped.");
var apps=eurekaClient.getInstancesByAppId(id);
// Use routing service?
// We use just a random robin here ...
if( apps && apps.length>0 ) {
var num = Math.floor(Math.random(apps.length));
return apps[num].homePageUrl;
} else {
throw new Error('Unable to find app with id '+id+' in eureka registry.');
}
}
const getConfig = async () => {
let config = {};
if( eurekaClient ) {
// Configuration endpoint is provided by the argus service
var url = getAppUrl('ARGUS') + 'config/' + parameter.name + '/'+ parameter.profile;
log.debug("Config url : "+url);
var result = await request(url);
const configRaw = JSON.parse( result );
if( configRaw.propertySources ) {
configRaw.propertySources.forEach( (propertySource) => {
if( propertySource.source ) {
for (var name in propertySource.source) {
if (propertySource.source.hasOwnProperty(name)) {
config[name] = propertySource.source[name];
}
}
}
});
}
for (var key in config) {
// skip loop if the property is from prototype
if (!config.hasOwnProperty(key)) continue;
if( typeof config[key] === "string" ) {
// If the config is a string we may have to do a substitute
config[key]=substitute(config[key],config);
}
}
} else {
log.warn('Eureka config not available. Registration was skipped.');
}
log.debug("Config "+JSON.stringify(config,0,2));
// Helper get function
config.get = (name) => {
return config[name];
}
return config;
}
const shutdown = ()=>{
if( eurekaClient ) {
log.debug("Shutdown. Unregistering from registry.");
eurekaClient.stop();
}
}
return {
getAppUrl : getAppUrl,
getConfig : getConfig,
shutdown : shutdown
}
}
module.exports.init = async function(parameter) {
log = parameter.logger || log;
if( !parameter.express ) {
throw new Error('Express app not set as express parameter.');
}
if( !parameter.name ) {
throw new Error('name parameter not set as parameter. You must provide a service name.');
}
// Determine the public host and port name
var hostname = process.env.PUBLIC_HOST || os.hostname();
var port = process.env.PUBLIC_PORT || parameter.port || parameter.express.address().port;
if( !port ) {
throw new Error('port can not be determined. Use the environment variable for PUBLIC_PORT, the port parameter or start the express listener first.');
}
var instanceId = hostname + ':' + parameter.name + ':'+port;
parameter.profile = process.env.APP_PROFILE || parameter.profile || '';
parameter.eureka=parameter.eureka || {};
var eureka = {
host : process.env.EUREKA_HOST || parameter.eureka.host || 'localhost',
port : process.env.EUREKA_PORT || parameter.eureka.port || 7261,
servicePath : process.env.EUREKA_SERVICEPATH || parameter.eureka.servicePath || '/eureka/apps',
maxRetries : process.env.EUREKA_RETRY || parameter.eureka.retry || 20
}
log.info('App name : ' + parameter.name);
log.info('App profile : ' + parameter.profile);
log.info('App port : ' + parameter.port);
log.info('App instance id : ' + instanceId);
log.info('App public host address : ' + hostname);
log.info('App public port : ' + port);
var skipRegistration = parameter.eureka.skip || process.env.EUREKA_SKIP_REGISTRATION;
if( !skipRegistration ) {
log.info('Eureka hostname : ' + eureka.host);
log.info('Eureka port : ' + eureka.port);
log.info('Eureka servicepath : ' + eureka.servicePath);
var eurekaClient = new Eureka({
// application instance information
instance: {
app: parameter.name,
hostName: hostname,
ipAddr: ip.address('public'), // Does this always work?
statusPageUrl: 'http://'+hostname+':'+port+'/manage/info',
healthCheckUrl: 'http://'+hostname+':'+port+'/manage/health',
instanceId : instanceId,
port: {
'$': port,
'@enabled': 'true',
},
vipAddress: parameter.name,
dataCenterInfo: {
'@class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
name: 'MyOwn', // This is needed by spring cloud / eureka / netflix whatever - if not set, a 400 is the response on registration
}
},
// eureka server host / port and configuration
eureka : eureka,
// forward logger
logger : log
});
// Wait for the eureka client start done
await new Promise( (resolve,reject) => {
eurekaClient.start( ()=>{
log.info('Eureka client start done.');
resolve();
});
});
} else {
log.info('Eureka client is not created and not started. Registration is skipped controlled by configuration.');
}
// Created discovery object.
var discovery = exported(eurekaClient, parameter);
// Initialize the express integration
expressIntegration.init(parameter, log, discovery);
return discovery;
}