Disabling "site deploy" and "space"
Moving "site config" utility to "config"
Taking out the scaffolding from "site create"
This commit is contained in:
Louis DeJardin 2012-03-19 22:32:31 -07:00
Родитель 225f24509d
Коммит f54ff2aec5
5 изменённых файлов: 1112 добавлений и 568 удалений

Просмотреть файл

@ -1,5 +1,6 @@
var https = require('https');
var tunnel = require('tunnel');
var xml2js = require('xml2js');
var log = require('winston');
@ -48,7 +49,11 @@ Channel.prototype.header = function (name, value) {
Channel.prototype.send = function (method, data, cb) {
var options = merge({}, this.options, { method: method });
options.agent = new https.Agent(options);
if (options.proxy) {
options.agent = tunnel.httpsOverHttp(options);
} else {
options.agent = new https.Agent(options);
}
log.silly('Request.Method', options.method);
log.silly('Request.Path', options.path);
@ -66,7 +71,7 @@ Channel.prototype.send = function (method, data, cb) {
}
});
res.on('end', function () {
if (++done==1) cb(null, {});
if (++done == 1) cb(null, {});
});
parser.on('end', function (result) {
if (result.Message && result.Code) {

Просмотреть файл

@ -11,7 +11,7 @@ exports.init = function (cli) {
var account = cli.category('account');
var config = account.category('config')
var config = cli.category('config')
.description('Manage settings in your config file.');
config.command('list')

Просмотреть файл

@ -3,6 +3,8 @@ var fs = require('fs');
var pfx2pem = require('../../util/certificates/pkcs').pfx2pem;
var Channel = require('../channel');
return;
exports.init = function (cli) {
var deploy = cli.category('site').category('deploy')

Разница между файлами не показана из-за своего большого размера Загрузить разницу

570
lib/cli/commands/site_.js Normal file
Просмотреть файл

@ -0,0 +1,570 @@
//if (!require('streamline/module')(module)) return;
var fs = require('fs');
var path = require('path');
var url = require('url');
var crypto = require('crypto');
var pfx2pem = require('../../util/certificates/pkcs').pfx2pem;
var Channel = require('../channel');
var async = require('async');
exports.init = function (cli) {
var log = cli.output;
var regions = [
{
prompt: 'South Central US',
webspace: 'southcentraluswebspace',
location: 'SouthCentralUS1',
plan: 'VirtualDedicatedPlan'
},
{
prompt: 'North Europe',
webspace: 'northeuropewebspace',
location: 'NorthEurope1',
plan: 'VirtualDedicatedPlan'
},
];
var regionPrompts = regions.map(function (region) { return region.prompt; });
function getChannel() {
var pem = cli.category('account').managementCertificate();
var channel = new Channel({
host: 'umapi-tc2.rdfetest.dnsdemo4.com',
port: 8443,
key: pem,
cert: pem
}).header('x-ms-version', '2011-02-25');
var proxyString =
process.env.HTTPS_PROXY ||
process.env.https_proxy ||
process.env.ALL_PROXY ||
process.env.all_proxy;
if (proxyString != undefined) {
channel = channel.add({ proxy: url.parse(proxyString) });
}
return channel;
}
var site = cli.category('site')
.description('Commands to manage your web sites.');
site.command('list')
.description('List your web sites.')
.option('-s, --subscription <id>', 'use the subscription id')
.execute(function (options, _) {
var parameters = {
subscription: cli.category('account').lookupSubscriptionId(options.subscription)
};
var spaces = site.doSpacesGet(parameters, _);
var sites = site.doSitesGet(parameters, _);
log.table(sites, function (row, site) {
row.cell('Name', site.Name);
row.cell('State', site.State);
row.cell('Host names', clean(site).HostNames);
});
});
function choose(data, callback) {
cli.choose(data, function (x) { callback(null, x); });
}
site.command('create <name>')
.description('Create a new web site and local directory.')
.option('-s, --subscription <id>', 'use the subscription id')
.option('--location <location>', 'the geographic region to create the website')
.option('--hostname <hostname>', 'custom host name to use')
.execute(function (name, options, _) {
var context = {
subscription: cli.category('account').lookupSubscriptionId(options.subscription),
site: {
name: name,
webspace: options.location,
hostname: options.hostname
}
};
if (context.site.webspace === undefined) {
log.help('Choose a region');
context.site.webspace = regions[choose(regionPrompts, _)].webspace;
}
site.doSitesPost(context, _);
site.doRepositoryPost(context, _);
var repo = site.doRepositoryGet(context, _);
log.help('To start adding content to the website, type in the following:');
log.help(' git init');
log.help(' git add .');
log.help(' git commit -m "initial commit"');
log.help(' git remote add azure ' + repo + context.site.name + '.git');
log.help(' git push azure master');
});
site.command('show <name>')
.description('Show details for a web sites.')
.option('-s, --subscription <id>', 'use the subscription id')
.execute(function (name, options, _) {
var context = {
subscription: cli.category('account').lookupSubscriptionId(options.subscription),
site: {
name: name
}
};
lookupSiteWebSpace(context, _);
log.info('Showing details for site');
log.verbose('Parameters', context);
var siteData = site.doSiteGet(context, _);
var configData = site.doSiteConfigGet(context, _);
var repositoryData = site.doRepositoryGet(context, _);
logEachData('Site', siteData);
logEachData('Config', configData);
log.data('Repository', clean(repositoryData));
});
function lookupSiteWebSpace(context, _) {
log.verbose('Attempting to locate site ', context.site.name);
var sites = site.doSitesGet(context, _);
for (var index in sites) {
if (sites[index].Name === context.site.name) {
log.verbose('Site located at ', sites[index].WebSpace);
context.site.webspace = sites[index].WebSpace;
}
}
if (context.site.webspace === undefined) {
throw new Error('Unable to locate site named ' + context.site.name);
}
}
site.command('delete <name>')
.description('Delete a web site.')
.option('-s, --subscription <id>', 'use the subscription id')
.execute(function (name, options, _) {
var context = {
subscription: cli.category('account').lookupSubscriptionId(options.subscription),
site: {
name: name
}
};
lookupSiteWebSpace(context, _);
var result = getChannel()
.path(context.subscription)
.path('services/webspaces')
.path(context.site.webspace)
.path('sites')
.path(context.site.name)
.DELETE(_);
});
site.command('start <name>')
.description('Start a web site.')
.option('-s, --subscription <id>', 'use the subscription id')
.execute(function (name, options, _) {
var context = {
subscription: cli.category('account').lookupSubscriptionId(options.subscription),
site: {
name: name
}
};
lookupSiteWebSpace(context, _);
var result = getChannel()
.path(context.subscription)
.path('services/webspaces')
.path(context.site.webspace)
.path('sites')
.path(context.site.name)
.header('Content-Type', 'application/xml')
.POST(function (req) {
req.write('<Site xmlns="http://schemas.microsoft.com/windowsazure">');
req.write('<State>');
req.write('Running');
req.write('</State>');
req.write('</Site>');
req.end();
}, _);
});
site.command('stop <name>')
.description('Stop a web site.')
.option('-s, --subscription <id>', 'use the subscription id')
.execute(function (name, options, _) {
var context = {
subscription: cli.category('account').lookupSubscriptionId(options.subscription),
site: {
name: name
}
};
lookupSiteWebSpace(context, _);
var result = getChannel()
.path(context.subscription)
.path('services/webspaces')
.path(context.site.webspace)
.path('sites')
.path(context.site.name)
.header('Content-Type', 'application/xml')
.POST(function (req) {
req.write('<Site xmlns="http://schemas.microsoft.com/windowsazure">');
req.write('<State>');
req.write('Stopped');
req.write('</State>');
req.write('</Site>');
req.end();
}, _);
});
/////////////////
// config and settings
site.findConfig = function () {
var scanFolder = process.cwd();
while (true) {
var azureFolder = path.join(scanFolder, '.azure');
// probe for config if azure folder exists
if (path.existsSync(azureFolder) &&
path.statSync(azureFolder).isDirectory()) {
// find a single .config file
var files = fs.readDirSync(azureFolder);
files = files.filter(function (filename) {
return endsWith(filename, '.config');
});
// return full path if it exists
if (files.length == 1) {
return path.join(azureFolder, files[0]);
}
}
// recurse upwards, or return null when that's no longer possible
try {
var parentFolder = path.dirname(scanFolder);
if (parentFolder === scanFolder || !path.exists(scanFolder)) {
return null;
}
}
catch (err) {
return null;
}
}
};
site.initConfig = function (config) {
var baseFolder = process.cwd();
var azureFolder = path.join(baseFolder, '.azure');
var baseName = crypto.randomBytes(16).toString('hex');
var configPath = path.join(azureFolder, baseName + '.config');
if (!path.exists(azureFolder)) {
log.silly('Creating folder', azureFolder);
fs.mkdirSync(azureFolder);
}
log.silly('Writing file', configPath);
var configText = JSON.stringify(config);
fs.writeFileSync(configPath, configText);
};
site.readConfig = function () {
var configPath = site.findConfig();
if (configPath === undefined) {
log.verbose('No site .azure/*.config file locate at current directory');
return null;
}
log.silly('Reading file', configPath);
var configText = fs.readFileSync(configPath);
var config = JSON.parse(configText);
log.json('silly', 'Site config', config);
return config;
};
site.writeConfig = function (config) {
var configPath = site.findConfig();
if (configPath === undefined) {
log.verbose('No site .azure/*.config file locate at current directory');
return null;
}
log.silly('Writing file', configPath);
var configText = JSON.stringify(config);
fs.writeFileSync(configPath, configText);
};
/////////////////
// remote api operations
site.doSitesPost = function (options, callback) {
log.info('Creating a new web site');
log.verbose('Subscription', options.subscription);
log.verbose('Webspace', options.site.webspace);
log.verbose('Site', options.site.name);
getChannel()
.path(options.subscription)
.path('services/webspaces')
.path(options.site.webspace)
.path('sites/')
.header('Content-Type', 'application/xml')
.POST(
writers.Site.xml(options.site),
function (err, result) {
if (err) {
logError('Failed to create site', err);
} else {
log.info('Created website at ', clean(result).HostNames);
log.verbose('Site', clean(result));
}
callback(err, result);
});
};
site.doRepositoryPost = function (options, callback) {
log.info('Initializing repository');
log.verbose('Subscription', options.subscription);
log.verbose('Webspace', options.site.webspace);
log.verbose('Site', options.site.name);
getChannel()
.path(options.subscription)
.path('services/webspaces')
.path(options.site.webspace)
.path('sites')
.path(options.site.name)
.path('repository')
.POST(
"",
function (err, result) {
if (err) {
logError('Failed to initialize repository', err);
} else {
log.info('Repository initialized');
}
callback(err, result);
});
};
site.doSpacesGet = function (options, _) {
log.verbose('Subscription', options.subscription);
var result = getChannel()
.path(options.subscription)
.path('services/webspaces/')
.GET(_);
log.json('silly', result);
return toArray(result.WebSpace);
};
site.doSitesGet = function (options, _) {
log.verbose('Subscription', options.subscription);
var spaces = site.doSpacesGet(options, _);
var channel = getChannel()
.path(options.subscription)
.path('services/webspaces');
var result = async.map(
spaces,
function (webspace, _) {
return channel
.path(webspace.Name)
.path('sites/')
.GET(_);
},
_);
var sites = [];
result.forEach(function (item) {
sites = sites.concat(toArray(item.Site));
});
result = sites;
log.json('verbose', sites);
return sites;
};
site.doSiteGet = function (options, callback) {
getChannel()
.path(options.subscription)
.path('services/webspaces')
.path(options.site.webspace)
.path('sites')
.path(options.site.name)
.GET(
function (err, result) {
if (err) {
logError('Failed to get site info', err);
} else {
log.verbose('Site', clean(result));
}
callback(err, result);
});
};
site.doSiteConfigGet = function (options, callback) {
getChannel()
.path(options.subscription)
.path('services/webspaces')
.path(options.site.webspace)
.path('sites')
.path(options.site.name)
.path('config')
.GET(
function (err, result) {
if (err) {
logError('Failed to get site config info', err);
} else {
log.verbose('SiteConfig', clean(result));
}
callback(err, result);
});
};
site.doRepositoryGet = function (options, callback) {
getChannel()
.path(options.subscription)
.path('services/webspaces')
.path(options.site.webspace)
.path('sites')
.path(options.site.name)
.path('repository')
.GET(
function (err, result) {
if (err) {
logError('Failed to get repository info', err);
} else {
log.verbose('Repository', clean(result));
}
callback(err, clean(result));
});
};
/////////////////
// helper methods
var writers = {
Site: {
xml: function (site) {
return function (req) {
req.write('<Site xmlns="http://schemas.microsoft.com/windowsazure">');
req.write('<HostNames>');
req.write('<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">');
req.write(site.name + '.antdir0.antares-test.windows-int.net');
req.write('</string>');
if (site.hostname) {
req.write('<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">');
req.write(site.hostname);
req.write('</string>');
}
req.write('</HostNames>');
req.write('<Name>');
req.write(site.name);
req.write('</Name>');
req.write('</Site>');
req.end();
};
}
}
};
function clean(source) {
if (typeof (source) === 'string') {
return source;
}
var target = {};
var hasString = false;
var hasNonString = false;
var stringValue = '';
for (var prop in source) {
if (prop == '@') {
continue;
} else {
if (prop === '#' || prop === 'string' || prop.substring(prop.length - 7) === ':string') {
hasString = true;
stringValue = source[prop];
} else {
hasNonString = true;
}
target[prop] = clean(source[prop]);
}
}
if (hasString && !hasNonString) {
return stringValue;
}
return target;
}
function logEachData(title, data) {
var cleaned = clean(data);
for (var property in cleaned) {
log.data(title + ' ' + property, cleaned[property]);
}
}
function logError(message, err) {
if (arguments.length == 1) {
err = message;
message = undefined;
} else {
log.error(message);
}
if (err) {
if (err.message) {
log.error(err.message);
log.verbose('stack', err.stack);
log.json('silly', err);
}
else if (err.Message) {
log.error(err.Message);
log.json('verbose', clean(err));
}
else {
log.error(err);
}
}
}
function isArray(testObject) {
return testObject && !(testObject.propertyIsEnumerable('length')) && typeof testObject === 'object' && typeof testObject.length === 'number';
}
function toArray(testObject) {
return isArray(testObject) ? testObject : typeof testObject === 'undefined' ? [] : [testObject];
}
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
};