/
analyze-os-repo-job.js
159 lines (141 loc) · 5.3 KB
/
analyze-os-repo-job.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
// Copyright 2015, EMC, Inc.
'use strict';
var di = require('di');
module.exports = analyzeOsRepoJobFactory;
di.annotate(analyzeOsRepoJobFactory, new di.Provide('Job.Os.Analyze.Repo'));
di.annotate(analyzeOsRepoJobFactory,
new di.Inject(
'Job.Base',
'Logger',
'Assert',
'Util',
'_',
'Promise',
'JobUtils.OsRepoTool'
)
);
function analyzeOsRepoJobFactory(
BaseJob,
Logger,
assert,
util,
_,
Promise,
repoTool
) {
var logger = Logger.initialize(analyzeOsRepoJobFactory);
/**
* This job will analyze the external OS repository, fetch some options from some repository
* files and pass these options to shared context:
* context.repoOptions = { xxx: xxx }
*
* @param {Object} options
* @param {Object} context
* @param {String} taskId
* @constructor
*/
function AnalyzeOsRepoJob(options, context, taskId) {
var self = this;
AnalyzeOsRepoJob.super_.call(self, logger, options, context, taskId);
self.nodeId = self.context.target;
assert.string(self.options.osName);
assert.string(self.options.repo);
// Both http://xxx/repo and http://xxx/repo/ should be valid and point to same repository,
// but our code prefer the previous one
if (self.options.repo) {
self.options.repo = self.options.repo.trim();
if (_.last(self.options.repo) === '/') {
self.options.repo = self.options.repo.substring(0, self.options.repo.length-1);
}
}
}
util.inherits(AnalyzeOsRepoJob, BaseJob);
/**
* @memberOf AnalyzeOsRepoJob
*/
AnalyzeOsRepoJob.prototype._run = function() {
var self = this;
return Promise.resolve().then(function() {
var handleFunc = self._findHandle(self.options.osName);
return handleFunc.call(self, self.options.repo);
}).then(function(result) {
self.context.repoOptions = _.merge(
result,
{
//I add some smart conversion for 'repo' in constructor, so I want it be exposed
//to shared context to avoid duplicate conversion
repo: self.options.repo
}
);
self._done();
}).catch(function(error) {
self._done(error);
logger.error('fail to analyze the os repository', {
error: error,
osName: self.osName,
repo: self.repo,
nodeId: self.nodeId,
context: self.context
});
});
};
/**
* A function that can be used to provide a function with no operations or side effects
* when lookup fails.
*
* @memberof AnalyzeOsRepoJob
* @return {Function} A noop/empty function.
* @private
*/
AnalyzeOsRepoJob.prototype._noop = function() {};
/**
* find the handle function for current OS
*
* @memberof AnalyzeOsRepoJob
* @param {String} osName - the name of target OS
* @return {Function} the handle function for the input OS, if no function is defined, it will
* return an empty function.
*/
AnalyzeOsRepoJob.prototype._findHandle = function(osName) {
var funcName = '_' + osName + 'Handle';
var handleFunc = this[funcName];
//Haven't defined a hanlding function for specified OS, it means it doesn't need to
//analyze the OS repository, return an empty for fluent promise chain
if (!handleFunc) {
return AnalyzeOsRepoJob.prototype._noop;
}
if (!_.isFunction(handleFunc)) {
throw(new Error('The handling for ' + osName + ' is not callable.'));
}
return handleFunc;
};
/**
* Fetch the ESXi installation options from exteranl repository
* @memberof AnalyzeOsRepoJob
* @param {String} repo - the external repository address.
* @return {Promise}
*/
AnalyzeOsRepoJob.prototype._ESXiHandle = function (repo) {
//first try the lower case because the installation has some problem when the repository
//is in upper case, but anyway we will try the upper case as a retry, in future we (maybe
//Vmware?) may have solution to fix the upper case problem.
return repoTool.downloadViaHttp(repo + '/boot.cfg').catch(function() {
return repoTool.downloadViaHttp(repo + '/BOOT.CFG');
}).then(function(data) {
var result = repoTool.parseEsxBootCfgFile(data);
//The following values are required for ESXi installation, add pre-checking for these
//value to provide error message earlier than template rendering, the time advance
//can be as much as 5-10min for some systems.
var requiredKeys = ['tbootFile', 'mbootFile', 'moduleFiles'];
_.forEach(requiredKeys, function(key) {
if (!result || !result.hasOwnProperty(key) || !result[key] ||
!_.isString(result[key])) {
throw new Error('The value \'' + key + '\' from ESXi repository is either '+
'missing or its format is not correct');
}
});
return result;
});
};
return AnalyzeOsRepoJob;
}