#!/usr/bin/env python import argparse import logging import logging.handlers import re import string import yaml from .core import arg_prompt from subprocess import check_output as cmd from subprocess import CalledProcessError from time import sleep class Resource: def __init__(self, args, config): self.__dict__.update(args) self.config = config self.logger = logging.getLogger(__name__) self.resource_id = '' _allowed = string.ascii_letters + string.digits for char in self.name: if char in _allowed: self.resource_id += char.lower() def create_resource(self): try: cmd([ self.config['google']['gam_command'], 'create', 'resource', self.resource_id, self.name, 'description', self.description, 'type', self.resource_type ]) except CalledProcessError: self.logger.error( 'Failed to create resource.', extra={'entity': self.name} ) exit(2) for n in range(5): try: resource_info = cmd([ self.config['google']['gam_command'], 'info', 'resource', self.resource_id ]) self.email = re.findall(b'Email: (.+)', resource_info)[0] break except CalledProcessError: self.logger.error( 'Unable to fetch resource. Retrying.', extra={'entity': self.name} ) sleep(5) else: self.logger.error( 'Permenant failure fetching resource. Exiting.', extra={'entity': self.name} ) exit(2) def add_resource_owners(self): for owner in self.owners: try: cmd([ self.config['google']['gam_command'], 'calendar', self.email.decode('utf-8'), 'add', 'owner', owner ]) except CalledProcessError: self.logger.warning( 'Failed to add {} as calendar owner'.format(owner), extra={'entity': self.name} ) continue def strip_global_access(self): try: cmd([ self.config['google']['gam_command'], 'calendar', self.email.decode('utf-8'), 'delete', 'user', 'domain' ]) cmd([ self.config['google']['gam_command'], 'calendar', self.email.decode('utf-8'), 'delete', 'user', 'default' ]) except CalledProcessError as e: self.logger.warning( 'Unable to remove domain-wide access to resource: {}'.format( e.output ), extra={'entity': self.name} ) def generate_canned_text(self): canned_text = ''' Hello, Your requested resource calendar has been created. As the requester of the resource, you and your fellow owners should now see it listed in your own Google calendar. Information about this new resource is as follows: Calendar Name: {} Calendar Type: {} Calendar Description: {} Calendar Owners: {} Calendar ID: {} If you have any questions about how to utilize this calendar, please consult the documentation found at the following link: http://documentation.its.umich.edu/node/660 If any of the above information is incorrect, please feel free to reply to this message and your incident will be automatically reopened.'''.format( self.name, self.resource_type, self.description, ','.join(self.owners), self.email.decode('utf-8') ) print( '============================================', canned_text ) def main(): helptext = '''examples: google-create-resource -n AL1-B1-2510 -o kmoss aaliyah google-create-resource --name AL1-B1-2510 --owners kmoss aaliyah --type 'Private Office' ''' parser = argparse.ArgumentParser( description='Creates a new resource in GSuite', epilog=helptext, formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument( '--name', '-n', help='The name to assign to the resource.', ) parser.add_argument( '--owners', '-o', help='Users to give management access to.', nargs='+', ) parser.add_argument( '--resource_type', '-t', help='The resource type.', default='' ) parser.add_argument( '--description', '-d', help='A description of the resource.', default='' ) parser.add_argument( '--config', '-c', help='The CAK config to use.', default='/etc/collab-admin-kit.yml' ) args = parser.parse_args() # Argument prompt fallback if not args.name: args.name = arg_prompt( 'Name to assign to the resource' ) args.owners = arg_prompt( '(optional) Resource owner uniqnames, separated by spaces', default='' ).split(' ') args.resource_type = arg_prompt( '(optional) Resource type', default='' ) args.description = arg_prompt( '(optional) Resource description', default='' ) # Argument sanity check _required = ['name'] for r in _required: try: if isinstance(r, str): assert getattr(args, r) if isinstance(r, tuple): assert getattr(args, r[0]) or getattr(args, r[1]) except AssertionError: print('Missing required argument {}'.format(r)) # Open the CAK Config with open(args.config) as stream: config = yaml.load(stream, Loader=yaml.BaseLoader) # Get the root logger and set the debug level logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # Create a syslog handler, set format, and associate. sh = logging.handlers.SysLogHandler( address='/dev/log', facility=config['general']['log_facility'] ) formatter = logging.Formatter(config['general']['log_format']) sh.setFormatter(formatter) logger.addHandler(sh) # Create a console handler, set format, and associate. ch = logging.StreamHandler() formatter = logging.Formatter( config['general']['console_format'], config['general']['date_format'] ) ch.setFormatter(formatter) logger.addHandler(ch) resource = Resource(vars(args), config) resource.create_resource() resource.add_resource_owners() resource.strip_global_access() resource.generate_canned_text() if __name__ == '__main__': main()