198 lines
6.5 KiB
JavaScript
198 lines
6.5 KiB
JavaScript
'use strict';
|
|
|
|
var common = require('./common.js'),
|
|
debug = require('debug')('e2e:appstore'),
|
|
request = require('superagent-sync'),
|
|
sleep = require('./shell.js').sleep,
|
|
stripe = require('stripe');
|
|
|
|
exports = module.exports = AppStore;
|
|
|
|
function AppStore(origin) {
|
|
this._origin = origin || process.env.APPSTORE_API_ORIGIN;
|
|
|
|
// credentials for api calls
|
|
this._credentials = {
|
|
password: null,
|
|
accessToken: null
|
|
};
|
|
|
|
this._adminCredentials = {
|
|
password: null,
|
|
accessToken: null
|
|
};
|
|
}
|
|
|
|
AppStore.prototype.getAccessToken = function (user) {
|
|
var res = request.get(this._origin + '/api/v1/login').auth(user.email, user.password).end();
|
|
common.verifyResponse2xx(res, 'Could not login as user:' + user.email + ' password:' + user.password);
|
|
return res.body.accessToken;
|
|
};
|
|
|
|
AppStore.prototype.getProfile = function () {
|
|
var res = request.get(this._origin + '/api/v1/profile').query({ accessToken: this._credentials.accessToken }).end();
|
|
return res.body.profile;
|
|
};
|
|
|
|
AppStore.prototype.setCredentials = function (password, accessToken) {
|
|
this._credentials = { password: password, accessToken: accessToken };
|
|
};
|
|
|
|
AppStore.prototype.setAdminCredentials = function (password, accessToken) {
|
|
this._adminCredentials = { password: password, accessToken: accessToken };
|
|
};
|
|
|
|
AppStore.prototype.getCloudrons = function () {
|
|
var res = request.get(this._origin + '/api/v1/cloudrons').query({ accessToken: this._credentials.accessToken, page: 1, per_page: 50 }).end();
|
|
return res.body.boxes;
|
|
};
|
|
|
|
AppStore.prototype.getCloudron = function (boxId) {
|
|
var res = request.get(this._origin + '/api/v1/cloudrons/' + boxId).query({ accessToken: this._credentials.accessToken }).retry(0).end();
|
|
if (res.statusCode === 404) return null;
|
|
common.verifyResponse2xx(res, 'Could not query cloudron status');
|
|
return res.body.box;
|
|
};
|
|
|
|
AppStore.prototype.waitForIP = function (boxId) {
|
|
process.stdout.write('Waiting for cloudron to get an IP.');
|
|
|
|
var res;
|
|
|
|
for (var i = 0; i < 60; i++) {
|
|
sleep(20);
|
|
process.stdout.write('.');
|
|
res = request.get(this._origin + '/api/v1/cloudrons/' + boxId).query({ accessToken: this._credentials.accessToken }).end();
|
|
common.verifyResponse2xx(res, 'Could not query cloudron status');
|
|
|
|
if (res.body.box.ip) {
|
|
debug();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!res.body || !res.body.box.ip) throw new Error('waitForIP timeout');
|
|
|
|
debug('Box IP:%s'.green, res.body.box.ip);
|
|
|
|
return res.body.box.ip;
|
|
};
|
|
|
|
AppStore.prototype.waitForCloudron = function (boxId) {
|
|
var creationTime = new Date();
|
|
process.stdout.write('Waiting for cloudron to come up.');
|
|
|
|
var boxInfo = null, res;
|
|
|
|
for (var i = 0; i < 120; i++) {
|
|
sleep(30);
|
|
process.stdout.write('.');
|
|
res = request.get(this._origin + '/api/v1/cloudrons/' + boxId).query({ accessToken: this._credentials.accessToken }).end();
|
|
common.verifyResponse2xx(res, 'Could not query cloudron status');
|
|
|
|
boxInfo = res.body.box;
|
|
if (boxInfo.status === 'ready') {
|
|
debug();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!boxInfo) throw new Error('waitForCloudron: could not get cloudron information');
|
|
|
|
// check for ready state
|
|
if (boxInfo.status !== 'ready') throw new Error('waitForCloudron: could not get cloudron status');
|
|
|
|
debug('Box created in %s minutes with IP:%s'.green, (new Date() - creationTime) / 60000, res.body.box.ip);
|
|
|
|
// even if the cloudron sent heartbeat to appstore, doesn't mean we can contact the cloudron thanks to DO networking insanity
|
|
process.stdout.write('Waiting for Cloudron to be reachable.');
|
|
for (i = 0; i < 60; i++) {
|
|
sleep(20);
|
|
process.stdout.write('.');
|
|
res = request.get('https://' + boxInfo.ip).end();
|
|
if (!res.error) break;
|
|
debug(res.error);
|
|
}
|
|
|
|
if (res.error) throw new Error('waitForCloudron: could not reach cloudron');
|
|
|
|
return boxInfo;
|
|
};
|
|
|
|
AppStore.prototype.createCloudron = function (box) {
|
|
var accessToken = this._credentials.accessToken;
|
|
var res = request.post(this._origin + '/api/v1/cloudrons').send(box).query({ accessToken: accessToken }).end();
|
|
common.verifyResponse2xx(res, 'Could not create cloudron %j', box);
|
|
|
|
debug('Cloudron %s created'.green, box.domain);
|
|
return res.body.box;
|
|
};
|
|
|
|
// Only allowed by admins
|
|
AppStore.prototype.deleteCloudron = function (box) {
|
|
var res = request.post(this._origin + '/api/v1/cloudrons/' + box.id)
|
|
.query({ accessToken: this._adminCredentials.accessToken })
|
|
.set('X-HTTP-Method-Override', 'DELETE')
|
|
.send({ password: this._adminCredentials.password })
|
|
.end();
|
|
common.verifyResponse2xx(res, 'Could not delete cloudron');
|
|
|
|
process.stdout.write('Waiting for Cloudron to disappear.');
|
|
for (var i = 0; i < 60; i++) {
|
|
if (this.getCloudron(box.id) === null) return;
|
|
|
|
sleep(20);
|
|
|
|
process.stdout.write('.');
|
|
}
|
|
|
|
throw new Error('deleteCloudron: timedout waiting for cloudron to disappear');
|
|
};
|
|
|
|
AppStore.prototype.getManifest = function (appId, version) {
|
|
var res = request.get(this._origin + '/api/v1/apps/' + appId + '/versions/' + version).end();
|
|
common.verifyResponse2xx(res, 'Could not get get app manifest');
|
|
return res.body.manifest;
|
|
};
|
|
|
|
AppStore.prototype.restore = function (boxId, backupId) {
|
|
var res = request.post(this._origin + '/api/v1/cloudrons/' + boxId + '/restore/' + encodeURIComponent(backupId)).query({ accessToken: this._credentials.accessToken }).end();
|
|
common.verifyResponse2xx(res, 'Could not restore cloudron');
|
|
};
|
|
|
|
AppStore.prototype.setupBilling = function (user, callback) {
|
|
var stripeApi = stripe(common.stripeSecret());
|
|
|
|
var that = this;
|
|
|
|
stripeApi.tokens.create({
|
|
card: {
|
|
number: '4242424242424242',
|
|
exp_month: 12,
|
|
exp_year: 2020,
|
|
cvc: '123'
|
|
}
|
|
}, function (error, token) {
|
|
if (error) return callback(error);
|
|
|
|
debug('Got stripe token', token.id);
|
|
|
|
var data = {
|
|
firstName: 'Max',
|
|
lastName: 'Mustermann',
|
|
company: 'Muster Inc',
|
|
street: '200 Muster Blvd.',
|
|
city: 'Muenster',
|
|
zip: '12312',
|
|
state: 'Munster',
|
|
country: 'DE',
|
|
billingToken: token.id
|
|
};
|
|
|
|
var res = request.put(that._origin + '/api/v1/users/' + user.id).send(data).query({ accessToken: that._credentials.accessToken }).end();
|
|
common.verifyResponse2xx(res, 'Could not setup billing');
|
|
|
|
callback(null);
|
|
});
|
|
};
|