Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

[VC update] rest-server #1831

Merged
merged 14 commits into from
Dec 26, 2018
2 changes: 1 addition & 1 deletion docs/rest-server/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -1018,4 +1018,4 @@ the version upgrade, which has no namespaces. They are called "legacy jobs", whi
but cannot be created. To figure out them, there is a "legacy: true" field of them in list apis.

In the next versions, all operations of legacy jobs may be disabled, so please re-create them as namespaced
job as soon as possible.
job as soon as possible.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
<value>1048576</value>
<description>default is 8GB, here we set 1024G</description>
</property>

<property>
<name>yarn.scheduler.configuration.store.class</name>
<value>zk</value>
<description>default is file, change it to zk to enable config by rest api</description>
</property>

<property>
<name>yarn.resourcemanager.scheduler.class</name>
Expand Down
3 changes: 2 additions & 1 deletion src/rest-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@
"node-cache": "~4.2.0",
"node-etcd": "~5.1.0",
"nyc": "~11.6.0",
"ssh-keygen": "~0.4.2",
"statuses": "~1.5.0",
"unirest": "~0.5.1",
"winston": "~2.4.0",
"ssh-keygen": "~0.4.2"
"xml2js": "~0.4.19"
},
"scripts": {
"coveralls": "nyc report --reporter=text-lcov | coveralls ..",
Expand Down
41 changes: 41 additions & 0 deletions src/rest-server/src/config/vc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// module dependencies
const Joi = require('joi');

// define the input schema for the 'update vc' api
const vcPutInputSchema = Joi.object().keys({
vcCapacity: Joi.number()
.integer()
.min(0)
.max(100)
.required(),
}).required();

// define the input schema for the 'put vc status' api
const vcStatusPutInputSchema = Joi.object().keys({
vcStatus: Joi.string()
.valid(['stopped', 'running'])
.required(),
}).required();

// module exports
module.exports = {
vcPutInputSchema: vcPutInputSchema,
vcStatusPutInputSchema: vcStatusPutInputSchema,
};
27 changes: 27 additions & 0 deletions src/rest-server/src/config/yarn.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

// module dependencies
const Joi = require('joi');
const unirest = require('unirest');
const config = require('./index');
const logger = require('./logger');

// get config from environment variables
let yarnConfig = {
Expand All @@ -26,8 +29,13 @@ let yarnConfig = {
'Accept': 'application/json',
},
yarnVcInfoPath: `${process.env.YARN_URI}/ws/v1/cluster/scheduler`,
webserviceUpdateQueueHeaders: {
'Content-Type': 'application/xml',
},
yarnVcUpdatePath: `${process.env.YARN_URI}/ws/v1/cluster/scheduler-conf`,
};


const yarnConfigSchema = Joi.object().keys({
yarnUri: Joi.string()
.uri()
Expand All @@ -37,6 +45,11 @@ const yarnConfigSchema = Joi.object().keys({
yarnVcInfoPath: Joi.string()
.uri()
.required(),
webserviceUpdateQueueHeaders: Joi.object()
.required(),
yarnVcUpdatePath: Joi.string()
.uri()
.required(),
}).required();

const {error, value} = Joi.validate(yarnConfig, yarnConfigSchema);
Expand All @@ -45,4 +58,18 @@ if (error) {
}
yarnConfig = value;


// framework launcher health check
if (config.env !== 'test') {
unirest.get(yarnConfig.yarnVcInfoPath)
.timeout(2000)
.end((res) => {
if (res.status === 200) {
logger.info('connected to yarn successfully');
} else {
throw new Error('cannot connect to yarn');
}
});
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fanyangCS

Shall we add a yarn dependency to rest server?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good question. the desired behavior is: if yarn is available, it works. if yarn is unavailable, the system says it doesn't support the feature yet.


In reply to: 239478932 [](ancestors = 239478932)

Copy link
Member Author

@mzmssg mzmssg Dec 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Gerhut @fanyangCS
I will move the validation somewhere to remove the dependency. But I think we need clarify vc firstly, it will affect our API design.

If we consider vc as the same concept of hadoop queue, moving the check to vc related API sounds reasonable, because only yarn provider this feature.
But if vc is designed as a abstract interface, hadoop queue is only one implementation. I think we need refactor our vc structure, to support other implementation. At least, some API coupling with hadoop queue shoulded be add to our doc.

module.exports = yarnConfig;
119 changes: 103 additions & 16 deletions src/rest-server/src/controllers/vc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,14 @@ const VirtualCluster = require('../models/vc');
const createError = require('../util/error');

/**
* Load virtual cluster and append to req.
* Validation, not allow operation to "default" vc.
*/
const load = (req, res, next, vcName) => {
new VirtualCluster(vcName, (vcInfo, error) => {
if (error) {
return next(createError.unknown(error));
}
req.vc = vcInfo;
const validate = (req, res, next, vcName) => {
if (vcName === 'default' && req.method !== 'GET') {
return next(createError('Forbidden', 'ForbiddenUserError', `Update operation to default vc isn't allowed`));
} else {
return next();
});
};

/**
* Get virtual cluster status.
*/
const get = (req, res) => {
return res.json(req.vc);
}
};

/**
Expand All @@ -59,9 +50,105 @@ const list = (req, res, next) => {
});
};

/**
* Get a vc.
*/
const get = (req, res, next) => {
const vcName = req.params.vcName;
VirtualCluster.prototype.getVc(vcName, (vcInfo, err) => {
if (err) {
return next(createError.unknown(err));
} else {
return res.status(200).json(vcInfo);
}
});
};


/**
* Add a vc.
*/
const update = (req, res, next) => {
const vcName = req.params.vcName;
const vcCapacity = parseInt(req.body.vcCapacity);
if (req.user.admin) {
VirtualCluster.prototype.updateVc(vcName, vcCapacity, (err) => {
if (err) {
return next(createError.unknown(err));
} else {
return res.status(201).json({
message: `update vc: ${vcName} to capacity: ${vcCapacity} successfully`,
});
}
});
} else {
next(createError('Forbidden', 'ForbiddenUserError', `Non-admin is not allowed to do this operation.`));
}
};


/**
* Update vc status, changing a vc from running to stopped a vc will only prevent new job in this vc.
*/
const updateStatus = (req, res, next) => {
const vcName = req.params.vcName;
const vcStatus = req.body.vcStatus;
if (req.user.admin) {
if (vcStatus === 'stopped') {
VirtualCluster.prototype.stopVc(vcName, (err) => {
if (err) {
return next(createError.unknown(err));
} else {
return res.status(201).json({
message: `stop vc ${vcName} successfully`,
});
}
});
} else if (vcStatus === 'running') {
VirtualCluster.prototype.activeVc(vcName, (err) => {
if (err) {
return next(createError.unknown(err));
} else {
return res.status(201).json({
message: `active vc ${vcName} successfully`,
});
}
});
} else {
next(createError('Bad Request', 'BadConfigurationError', `Unknown vc status: ${vcStatus}`));
}
} else {
next(createError('Forbidden', 'ForbiddenUserError', `Non-admin is not allowed to do this operation.`));
}
};


/**
* Remove a vc.
*/
const remove = (req, res, next) => {
const vcName = req.params.vcName;
if (req.user.admin) {
VirtualCluster.prototype.removeVc(vcName, (err) => {
if (err) {
return next(createError.unknown(err));
} else {
return res.status(201).json({
message: `remove vc: ${vcName} successfully`,
});
}
});
} else {
next(createError('Forbidden', 'ForbiddenUserError', `Non-admin is not allowed to do this operation.`));
}
};

// module exports
module.exports = {
load,
get,
list,
update,
remove,
updateStatus,
validate,
};
Loading