sendak
Version:
Sendak manages metadata for cloud deployments
150 lines (136 loc) • 4.46 kB
JavaScript
;
// per https://github.com/18F/Sendak/issues/87
//
// arguments:
// required:
// - given name (jane)
// - surname (arc)
// - project (devops)
// optional:
// - github id (janearc)
// - filename you'd like written to (/tmp/foo.png)
//
// returns:
// a one-time password (json)
// an iam login id
// a qr code on disk (a file name)
//
var meta = function () {
return {
'args' : {
'given-name' : [ String, 'Specify given name (e.g., jane)' ],
'sur-name' : [ String, 'Specify surname (e.g., arc)' ],
'github-id' : [ String, 'Where to store the resultant QR code' ]
},
'name' : 'onboard-user',
'abstract' : 'create a new user with identity in Sendak and an account in IAM'
}
}
var plug = function (args) {
var Sendak = require( '../../lib/js/sendak.js' )
, iam = Sendak.iam
, rm = Sendak.rm
, stdout = Sendak.stdout
, stderr = Sendak.stderr
, logger = Sendak.getlogger()
, fs = require('fs')
, q = require('q')
, dg = require('deep-grep')
// Promises, promises
// https://www.youtube.com/watch?v=H8Q83DPZy6E
, defs = {
arn : q.defer(),
mfa : q.defer(),
file : q.defer(),
serial : q.defer()
}
// Get an acceptable username and metadata object for the user
//
, username = Sendak.users.sendak.util.name_to_userid( args['given-name'], args['sur-name'] )
, pmetadata = rm.new_object( 'user' )
// Get a list of our users in AWS
//
, paws_users = Sendak.users.iam.get( { 'user-name': true } )
q.longStackSupport = true;
q.onerror = true;
paws_users.then( function (users) {
var extant = dg.deeply( users, function (t) {
if (t == username) { return true }
}, {
'check-keys': false,
'check-values': true,
'return-hash-tuples': true
} );
if (extant.length) {
// It looks like this user exists in IAM and we can't proceed.
//
logger.error( 'Appears '.concat( username, ' already exists in IAM.' ) );
logger.error( extant );
process.exit( -255 );
}
else {
Sendak.users.iam.create( { 'user-name' : username.concat( nonce() ) } ).then( function (response) {
var awsuser = response.User;
// Now we have a user from Amazon, grab the metadata from RM, and store
// it back in the database.
//
pmetadata.then( function (metadata) {
// Did they specify a github id at invocation?
//
if (args['github-id']) {
metadata['github-id'] = args['github-id'];
}
var mog = Sendak.users.mogrify.aws_to_sendak( awsuser );
Sendak.users.sendak.create( dg.coalesce( mog, metadata, { 'return-clone': true } ) )
.then( function (user) {
// Creation of a sendak user was successful, creation of iam user was
// successful, so resolve those values, and create an MFA device and
// tell the caller.
//
defs.serial.resolve( user.serial );
defs.arn.resolve( mog.arn );
Sendak.users.iam.mfa.create( { 'user-name': mog['user-name'] } )
.then( function (mfadata) {
defs.mfa.resolve( mfadata )
} );
} );
} )
} );
}
} );
defs.serial.promise.then( function (serial) {
defs.arn.promise.then( function (arn) {
defs.mfa.promise.then( function (mfadata) {
var mfadev = Sendak.users.mogrify.aws_mfa_to_sendak( mfadata );
// Actually write the QR PNG
//
logger.info( 'calling fs.write ' + args['output-file'] );
fs.writeFile( args['output-file'], mfadev.contents, function (err, bw, buf) {
if (err) {
logger.info( 'error during write.' );
defs.file.resolve( err );
}
else {
logger.info( 'writing file.' );
defs.file.resolve( args['output-file'] )
}
} )
defs.file.promise.then( function (f) {
if (typeof f == 'error') {
logger.error( 'Failure to write qr code: '.concat( f.toString() ) );
process.exit( -255 );
}
if (typeof f == 'string') {
logger.info( 'this user has an MFA device id of '.concat( mfadev.sn ) );
logger.info( 'hurrah, sendak user with serial '.concat( serial, ' created.' ) );
logger.info( 'this corresponds to IAM user '.concat( arn ) );
logger.info( 'their QR code is on-disk at '.concat( f ) );
}
} )
} )
} );
} );
}
module.exports = plug;
plug.meta = meta;
// @janearc 🐙👾 // jane@cpan.org // vim:tw=80:ts=2:noet