Exemplo n.º 1
0
    def __init__(self, user, password):

        self.inst = LDAP(user, password)
        dn = 'cn=admin,dc=canvas,dc=virtue,dc=com'
        self.inst.get_ldap_connection()
        self.inst.conn.simple_bind_s(dn, 'Test123!')

        self.rdb_manager = RethinkDbManager()

        self.conn = None
Exemplo n.º 2
0
    def __init__(self,
                 ldap_user,
                 ldap_password,
                 role_id,
                 user,
                 virtue_id,
                 role=None):
        super(CreateVirtueThread, self).__init__()

        self.inst = LDAP(ldap_user, ldap_password)

        self.role_id = role_id
        self.role = role

        self.username = user
        self.virtue_id = virtue_id
Exemplo n.º 3
0
    def __init__(self,
                 ldap_user,
                 ldap_password,
                 role,
                 base_img_name,
                 use_ssh=True):
        super(AssembleRoleThread, self).__init__()

        self.inst = LDAP(ldap_user, ldap_password)

        # Going to need to write to LDAP
        # self.inst.bind_ldap()
        dn = 'cn=admin,dc=canvas,dc=virtue,dc=com'
        self.inst.get_ldap_connection()
        self.inst.conn.simple_bind_s(dn, 'Test123!')

        self.role = role

        self.base_img_name = base_img_name
        self.use_ssh = use_ssh
Exemplo n.º 4
0
class EndPoint_Security:

    rethinkdb_host = 'rethinkdb.galahad.com'
    ca_cert = '/var/private/ssl/rethinkdb_cert.pem'
    excalibur_key_file = '/var/private/ssl/excalibur_private_key.pem'
    virtue_key_dir = os.environ['HOME'] + '/user-keys'
    wait_for_ack = 30  # seconds

    def __init__(self, user, password):

        self.inst = LDAP(user, password)
        dn = 'cn=admin,dc=canvas,dc=virtue,dc=com'
        self.inst.get_ldap_connection()
        self.inst.conn.simple_bind_s(dn, 'Test123!')

        self.rdb_manager = RethinkDbManager()

        self.conn = None

    def transducer_list(self):
        '''
        Lists all transducers currently available in the system

        Args:

        Returns:
            list: Transducer objects for known transducers
        '''

        try:
            transducers_raw = self.inst.get_objs_of_type('OpenLDAPtransducer')
            if transducers_raw is None:
                return self.__error(
                    'unspecifiedError',
                    details='Unable to get transducer objects from LDAP')

            transducers_ret = []

            for transducer in transducers_raw:
                ldap_tools.parse_ldap(transducer[1])
                transducers_ret.append(transducer[1])

            return json.dumps(transducers_ret)

        except Exception as e:
            return self.__error('unspecifiedError',
                                details='Unable to get transducer objects: ' +
                                str(e))

    def transducer_get(self, transducerId):
        '''
        Gets information about the indicated Transducer. Does not include information about any
        instantiation in Virtues.

        Args:
            transducerId (str): The ID of the Transducer to get.

        Returns:
            Transducer: information about the indicated transducer
        '''

        try:
            transducer = self.inst.get_obj('cid', transducerId,
                                           'openLDAPtransducer', True)
            if transducer is None or transducer == ():
                return self.__error('invalidTransducerId')
            ldap_tools.parse_ldap(transducer)

            if DEBUG_PERMISSIONS:
                return json.dumps(transducer)

            return json.dumps(transducer)

        except Exception as e:
            return self.__error('unspecifiedError',
                                details='Unable to get transducer object: ' +
                                str(e))

    def transducer_enable(self, transducerId, virtueId, configuration):
        '''
        Enables the indicated Transducer in the indicated Virtue.

        Args:
            transducerId (str) : The ID of the Transducer to enable.
            virtueId (str)     : The ID of the Virtue in which to enable the Transducer.
            configuration (object): The configuration to apply to the Transducer when it is enabled. Format
                        is Transducer-specific. This overrides any existing configuration with the same keys.

        Returns:
            bool: True if the transducer was enabled, false otherwise

        '''
        ret = self.__enable_disable(transducerId, virtueId, configuration,
                                    True)
        if type(ret) is bool and ret == True:
            return self.__error('success')
        return ret

    def transducer_disable(self, transducerId, virtueId):
        '''
        Disables the indicated Transducer in the indicated Virtue

        Args:
            transducerId (str) : The ID of the Transducer to disable
            virtueId (str)     : The ID of the Virtue in which to enable the Transducer.

        Returns:
            bool: True if the transducer was enabled, false otherwise
        '''
        ret = self.__enable_disable(transducerId, virtueId, None, False)
        if type(ret) is bool and ret == True:
            return self.__error('success')
        return ret

    def transducer_get_enabled(self, transducerId, virtueId):
        '''
        Gets the current enabled status for the indicated Transducer in the indicated Virtue.

        Args:
            transducerId (str) : The ID of the Transducer
            virtueId (str)     : The ID of the Virtue in which to enable the Transducer.

        Returns:
            bool: True if the Transducer is enabled in the Virtue, false if it is not

        '''

        if self.conn is None:
            self.__connect_rethinkdb()
        try:
            row = r.db('transducers').table('acks')\
                .get([virtueId, transducerId]).run(self.conn)
        except r.ReqlError as e:
            return self.__error(
                'unspecifiedError',
                details='Failed to get info about transducer: ' + str(e))

        # Transducers are enabled by default
        if row is None:
            return json.dumps({'enabled': True})

        verified = self.__verify_message(row)
        if (verified != True):
            return verified

        return json.dumps({'enabled': row['enabled']})

    def transducer_get_configuration(self, transducerId, virtueId):
        '''
        Gets the current configuration for the indicated Transducer in the indicated Virtue.

        Args:
            transducerId (str) : The ID of the Transducer
            virtueId (str)     : The ID of the Virtue in which to enable the Transducer.

        Returns:
            TransducerConfig: Configuration information for the indicated Transducer in the indicated Virtue
        '''

        if self.conn is None:
            self.__connect_rethinkdb()
        try:
            row = r.db('transducers').table('acks')\
                .get([virtueId, transducerId]).run(self.conn)
        except r.ReqlError as e:
            return self.__error(
                'unspecifiedError',
                details='Failed to get info about transducer: ' + str(e))

        # If there's no row, there's no set config
        if row is None:
            return json.dumps(None)

        verified = self.__verify_message(row)
        if (verified != True):
            return verified

        # By definition, the configuration is a JSON object
        return row['configuration']

    def transducer_list_enabled(self, virtueId):
        '''
        Lists all Transducers currently that are currently enabled in the indicated Virtue.

        Args:
            virtueId (str)     : The ID of the Virtue in which to enable the Transducer.

        Returns:
            list(Transducer): List of enabled transducers within the specified Virtue
        '''

        enabled_transducers = []

        if self.conn is None:
            self.__connect_rethinkdb()
        try:
            for row in r.db('transducers').table('acks')\
                .filter({'virtue_id': virtueId}).run(self.conn):

                verified = self.__verify_message(row)
                if (verified != True):
                    return verified

                if ('enabled' in row) and row['enabled']:
                    enabled_transducers.append(row['transducer_id'])

        except r.ReqlError as e:
            return self.__error('unspecifiedError',
                                details='Failed to get enabled transducers: ' +
                                str(e))

        return json.dumps(enabled_transducers)

    def transducer_all_virtues(self, transducerId, configuration, isEnabled):
        '''
        Sets the given transducer to true for all running and stopped virtues.
        Updates roles and starting configuration to match, so additionally created
        or started virtues will share the same config.

        :param transducerId:
        :param isEnabled::o
        :return:
        '''

        try:
            ret = self.__update_roles_transducer(transducerId, isEnabled)
            if ret != True:
                return ret

            ret = self.__update_transducer_starting_config(
                transducerId, configuration)
            if ret != True:
                return ret

            virtues_raw = self.inst.get_objs_of_type('OpenLDAPvirtue')
            if (virtues_raw == None):
                return json.dumps(ErrorCodes.user['unspecifiedError'])

            for virtue in virtues_raw:
                ldap_tools.parse_ldap(virtue[1])
                ret = self.__enable_disable(transducerId, virtue[1]['id'],
                                            configuration, isEnabled)
                if (ret != True):
                    return json.dumps(ret)

            return self.__error('success')
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def __connect_rethinkdb(self):
        # RethinkDB connection
        # This connection will fail if setup_rethinkdb.py hasn't been run, because
        # there won't be an excalibur user and it won't have the specified password.
        with open(self.excalibur_key_file, 'r') as f:
            key = f.read()
            self.excalibur_key = RSA.importKey(key)
            try:
                self.conn = r.connect(host=self.rethinkdb_host,
                                      user='******',
                                      password=key,
                                      ssl={'ca_certs': self.ca_cert})
            except r.ReqlDriverError as e:
                return self.__error('unspecifiedError', details=\
                    'Failed to connect to RethinkDB at host: ' + \
                    self.rethinkdb_host + ' because: ' + str(e))
        return True

    def __enable_disable(self, transducerId, virtueId, configuration,
                         isEnable):

        # Make sure transducer exists
        transducer = self.inst.get_obj('cid', transducerId,
                                       'openLDAPtransducer', True)
        if transducer is None or transducer == ():
            return self.__error('invalidTransducerId')

        ldap_tools.parse_ldap(transducer)

        # Make sure virtue exists
        virtue = self.inst.get_obj('cid', virtueId, 'openLDAPvirtue', True)
        if virtue is None or virtue == ():
            return self.__error('invalidVirtueId')
        ldap_tools.parse_ldap(virtue)
        virtue_running = (virtue['state'] == 'RUNNING')

        # Change the ruleset
        ret = self.__change_ruleset(virtueId,
                                    transducerId,
                                    transducer['type'],
                                    isEnable,
                                    virtue_running,
                                    config=configuration)
        if ret != True:
            return ret

        if virtue_running:
            # Update the virtue's list of transducers
            # Call loads because transducer_list_enabled returns a string
            new_t_list = json.loads(self.transducer_list_enabled(virtueId))
            if type(new_t_list) is dict and new_t_list['status'] == 'failed':
                # Couldn't retrieve new list of transducers
                return self.__error(
                    'unspecifiedError',
                    details='Unable to update virtue\'s list of transducers')

            virtue['transducerIds'] = new_t_list
            ret = self.inst.modify_obj(
                'cid', virtueId, ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue'),
                'OpenLDAPvirtue', True)

        else:
            # Update list of transducers in LDAP without syncing it
            # with rethink (Non-running virutes are not in rethink)
            new_t_list = virtue['transducerIds']

            if isEnable:
                if transducerId not in new_t_list:
                    new_t_list.append(transducerId)
            else:
                if transducerId in new_t_list:
                    new_t_list.remove(transducerId)

            virtue['transducerIds'] = new_t_list
            ret = self.inst.modify_obj(
                'cid', virtueId, ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue'),
                'OpenLDAPvirtue', True)

        if ret != 0:
            return self.__error(
                'unspecifiedError',
                details='Unable to update virtue\'s list of transducers')

        return True

    def __sign_message(self, row):
        required_keys = [
            'virtue_id', 'transducer_id', 'type', 'configuration', 'enabled',
            'timestamp'
        ]
        if not all([(key in row) for key in required_keys]):
            return (False,
                self.__error('unspecifiedError', details='Missing required keys in row: ' +\
                str(filter((lambda key: key not in row), required_keys))))

        message = '|'.join([
            row['virtue_id'], row['transducer_id'], row['type'],
            str(row['configuration']),
            str(row['enabled']),
            str(row['timestamp'])
        ])
        h = SHA.new(str(message))
        signer = PKCS1_v1_5.new(self.excalibur_key)
        signature = signer.sign(h)
        return (True, signature)

    def __verify_message(self, row):
        if row is None:
            return self.__error('unspecifiedError',
                                details='No match found in database')

        required_keys = [
            'virtue_id', 'transducer_id', 'type', 'configuration', 'enabled',
            'timestamp', 'signature'
        ]
        if not all([(key in row) for key in required_keys]):
            return self.__error('unspecifiedError', details='Missing required keys in row: ' +\
                str(filter((lambda key: key not in row), required_keys)))

        message = '|'.join([
            row['virtue_id'], row['transducer_id'], row['type'],
            str(row['configuration']),
            str(row['enabled']),
            str(row['timestamp'])
        ])

        virtue_public_key = os.path.join(self.virtue_key_dir,
                                         row['virtue_id'] + '.pem.pub')
        if not os.path.isfile(virtue_public_key):
            return self.__error('invalidOrMissingParameters', details=\
                'No file found for Virtue public key at: ' + \
                virtue_public_key)
        with open(virtue_public_key) as f:
            virtue_key = RSA.importKey(f.read())

        h = SHA.new(str(message))
        verifier = PKCS1_v1_5.new(virtue_key)
        verified = verifier.verify(h, row['signature'])
        if not verified:
            printable_msg = deepcopy(row)
            del printable_msg['signature']
            return self.__error('unspecifiedError', details=\
                'Unable to validate signature of ACK message: ' + \
                json.dumps(printable_msg, indent=2))

        return True

    def __change_ruleset(self,
                         virtue_id,
                         trans_id,
                         transducer_type,
                         enable,
                         virtue_running,
                         config=None):
        if self.conn is None:
            ret = self.__connect_rethinkdb()
            # Return if error
            if ret != True:
                return ret

        if type(transducer_type) is list:
            transducer_type = transducer_type[0]

        timestamp = int(time.time())

        row = {
            'id': [virtue_id, trans_id],
            'virtue_id': virtue_id,
            'transducer_id': trans_id,
            'type': transducer_type,
            'configuration': config,
            'enabled': enable,
            'timestamp': timestamp
        }
        (success, signature) = self.__sign_message(row)
        if not success:
            # Return error code
            return signature

        row['signature'] = r.binary(signature)

        # Send command to change ruleset
        try:
            res = r.db('transducers').table('commands')\
                .insert(row, conflict='replace').run(self.conn)
            if res['errors'] > 0:
                return self.__error(
                    'unspecifiedError',
                    details=
                    'Failed to insert into commands table; first error: ' +
                    res['first_error'])
        except r.ReqlError as e:
            return self.__error(
                'unspecifiedError',
                details='Failed to insert into commands table: ' + str(e))

        # If the virtue isn't running yet, don't bother waiting for an ACK
        if not virtue_running:
            return True

        # Wait for ACK from the virtue that the ruleset has been changed
        # try:
        cursor = r.db('transducers').table('acks')\
            .get([virtue_id, trans_id])\
            .changes(squash=False).run(self.conn)
        # except r.ReqlError as e:
        #       print 'ERROR: Failed to read from the ACKs table because:', e
        #       return False

        retry = True
        while retry:
            try:
                retry = False
                # Wait max 30 seconds - if we miss the real ACK, hopefully
                # at least the next heartbeat will suffice
                print 'INFO: Waiting for ACK'
                change = cursor.next(wait=self.wait_for_ack)
                row = change['new_val']

                verified = self.__verify_message(row)
                if (verified != True):
                    return verified

                if row['timestamp'] >= timestamp:
                    if row['enabled'] == enable:
                        print 'INFO: ACK received!'
                        return True
                    else:
                        return self.__error(
                            'unspecifiedError',
                            details=
                            'Received ACK with incorrect value for enabled: ' +
                            str(enable) + ' vs ' + str(row['enabled']))
                else:
                    print 'WARN: Timestamp incorrect:', timestamp, row[
                        'timestamp']
                    # Retry once in case that was just a wayward ACK
                    retry = True

            except (r.ReqlCursorEmpty, r.ReqlDriverError) as e:
                return self.__error(
                    'unspecifiedError',
                    details='Failed to receive ACK before timeout')
            finally:
                cursor.close()
        return self.__error('unspecifiedError',
                            details='Failed to receive ACK before timeout')

    def __error(self, key, details=None):
        if key not in ErrorCodes.security:
            print "Error type '" + key + "' not found!  Using UnspecifiedError."
            key = 'unspecifiedError'
        e = deepcopy(ErrorCodes.security[key])
        if details is not None:
            # e['details'] = details
            e['result'].append(details)
        return json.dumps(e)

    def __update_roles_transducer(self, transducerId, isEnabled):
        # Make sure transducer exists
        transducer = self.inst.get_obj('cid', transducerId,
                                       'openLDAPtransducer', True)
        if transducer is None or transducer == ():
            return self.__error('invalidTransducerId')

        try:
            ldap_roles = self.inst.get_objs_of_type('OpenLDAProle')
            assert ldap_roles != None

            roles = ldap_tools.parse_ldap_list(ldap_roles)

            for role in roles:
                new_t_list = role['startingTransducerIds']

                if isEnabled:
                    if transducerId not in new_t_list:
                        new_t_list.append(transducerId)
                else:
                    if transducerId in new_t_list:
                        new_t_list.remove(transducerId)

                role['startingTransducerIds'] = new_t_list
                ret = self.inst.modify_obj(
                    'cid', role['id'],
                    ldap_tools.to_ldap(role,
                                       'OpenLDAProle'), 'OpenLDAProle', True)
                if ret != 0:
                    return self.__error(
                        'unspecifiedError',
                        details='Unable to update virtue\'s list of transducers'
                    )
            return True

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def __update_transducer_starting_config(self, transducerId, configuration):
        transducer = self.inst.get_obj('cid', transducerId,
                                       'openLDAPtransducer', True)
        if transducer is None or transducer == ():
            return self.__error('invalidTransducerId')

        ldap_tools.parse_ldap(transducer)
        transducer['startingConfiguration'] = configuration

        ret = self.inst.modify_obj(
            'cid', transducer['id'],
            ldap_tools.to_ldap(transducer, 'openLDAPtransducer'),
            'openLDAPtransducer', True)
        if ret != 0:
            return self.__error(
                'unspecifiedError',
                details='Unable to update virtue\'s list of transducers')

        return True
Exemplo n.º 5
0
def update_ldap_users_from_ad():
    # Setup the ldap connection
    dn = "cn=admin,dc=canvas,dc=virtue,dc=com"
    ldap = LDAP('', '')
    ldap.get_ldap_connection()
    # FIXME - Figure out a soluton for the Hardcoded password
    # TODO - Fix Hardcoded password for ldap and AD connection
    ldap.conn.simple_bind_s(dn, "Test123!")

    # Bind the AD connection
    ad = LDAP('*****@*****.**', 'Test123!')
    ad.bind_ad()

    # Query AD for all users
    ad_users = ad.query_ad('objectClass', 'user')

    ldap_usernames = get_ldap_usernames(ldap)

    # Go through all users in AD
    for user in ad_users:
        cn = user[1]['cn'][0]
        ad_username = user[1]['sAMAccountName'][0]
        # If a username in AD is not found in ldap then add it
        if ad_username not in ldap_usernames:
            new_user = {
                'username': ad_username,
                'authorizedRoleIds': [],
                'name': cn
            }
            new_ldap_user = ldap_tools.to_ldap(new_user, 'OpenLDAPuser')
            ldap.add_obj(new_ldap_user, 'users', 'cusername', throw_error=True)

            # Check to make sure the key directory exists
            if (not os.path.exists('{0}/user-keys'.format(
                    os.environ['HOME']))):
                os.mkdir('{0}/user-keys'.format(os.environ['HOME']))

            # Create/Add keys for each user
            subprocess.check_call([
                'ssh-keygen', '-t', 'rsa', '-f',
                '{}/user-keys/{}.pem'.format(os.environ['HOME'], ad_username),
                '-C', '"For Virtue user {0}"'.format(ad_username), '-N', ''
            ])

            # Create a dummy kerberos file for the user.
            # It'll be regenerated as soon as the user logs in.
            with open('/tmp/krb5cc_{}'.format(ad_username), 'w') as f:
                f.write("Error 404: Easter Egg text not found")

    return ldap
Exemplo n.º 6
0
class AssembleRoleThread(threading.Thread):
    def __init__(self,
                 ldap_user,
                 ldap_password,
                 role,
                 base_img_name,
                 use_ssh=True):
        super(AssembleRoleThread, self).__init__()

        self.inst = LDAP(ldap_user, ldap_password)

        # Going to need to write to LDAP
        # self.inst.bind_ldap()
        dn = 'cn=admin,dc=canvas,dc=virtue,dc=com'
        self.inst.get_ldap_connection()
        self.inst.conn.simple_bind_s(dn, 'Test123!')

        self.role = role

        self.base_img_name = base_img_name
        self.use_ssh = use_ssh

    def run(self):

        self.role['state'] = 'CREATING'

        ldap_role = ldap_tools.to_ldap(self.role, 'OpenLDAProle')
        ret = self.inst.add_obj(ldap_role, 'roles', 'cid', throw_error=True)

        assert ret == 0

        virtue_path = 'images/non_provisioned_virtues/' + self.role[
            'id'] + '.img'
        key_path = USER_KEY_DIR + '/default-virtue-key.pem'

        valor_manager = ValorManager()

        try:

            # Create the role standby image files
            standby_roles = StandbyRoles(self.base_img_name, self.role)
            standby_roles.create_role_image_file()

            if (self.use_ssh):
                # Launch by adding a 'virtue' to RethinkDB
                valor = valor_manager.get_empty_valor()
                virtue_ip = valor_manager.add_virtue(
                    valor['address'], valor['valor_id'], self.role['id'],
                    virtue_path, True)  # send role_create=True)

                time.sleep(5)

                # Get Docker login command
                # Use the AWS Account ID of the Account which has the docker registry,
                # currently this is in the StarLab account.
                docker_cmd = subprocess.check_output(
                    shlex.split(
                        'aws ecr get-login --registry-ids {} --no-include-email '
                        '--region us-east-2'.format(AWS_ECR_ACCOUNT_NUMBER)))

                print('docker_cmd: ' + docker_cmd)

                # Run assembler
                assembler = Assembler(work_dir='{0}/.{1}_assembly'.format(
                    os.environ['HOME'], self.role['id']))
                assembler.assemble_running_vm(self.role['applicationIds'],
                                              docker_cmd, key_path, virtue_ip)

            # Create the virtue standby image files
            standby_virtues = StandbyVirtues(self.role['id'])
            standby_virtues.create_standby_virtues()

            self.role['state'] = 'CREATED'
            ldap_role = ldap_tools.to_ldap(self.role, 'OpenLDAProle')
            ret = self.inst.modify_obj('cid',
                                       self.role['id'],
                                       ldap_role,
                                       objectClass='OpenLDAProle',
                                       throw_error=True)

            assert ret == 0

        except:
            print('Error while assembling role {0}:\n{1}'.format(
                self.role['id'], traceback.format_exc()))

            self.role['state'] = 'FAILED'
            ldap_role = ldap_tools.to_ldap(self.role, 'OpenLDAProle')
            ret = self.inst.modify_obj('cid',
                                       self.role['id'],
                                       ldap_role,
                                       objectClass='OpenLDAProle',
                                       throw_error=True)
        finally:
            if valor_manager.rethinkdb_manager.get_virtue(self.role['id']):
                valor_manager.rethinkdb_manager.remove_virtue(self.role['id'])
Exemplo n.º 7
0
class CreateVirtueThread(threading.Thread):
    def __init__(self,
                 ldap_user,
                 ldap_password,
                 role_id,
                 user,
                 virtue_id,
                 role=None):
        super(CreateVirtueThread, self).__init__()

        self.inst = LDAP(ldap_user, ldap_password)

        self.role_id = role_id
        self.role = role

        self.username = user
        self.virtue_id = virtue_id

    def run(self):

        thread_list.append(self)

        # Going to need to write to LDAP
        # self.inst.bind_ldap()
        dn = 'cn=admin,dc=canvas,dc=virtue,dc=com'
        self.inst.get_ldap_connection()
        self.inst.conn.simple_bind_s(dn, 'Test123!')

        if (self.role == None):
            role = self.inst.get_obj('cid',
                                     self.role_id,
                                     objectClass='OpenLDAProle')
            if (role == () or role == None):
                return
            ldap_tools.parse_ldap(role)
        else:
            role = self.role

        virtue = {
            'id': self.virtue_id,
            'username': self.username,
            'roleId': self.role_id,
            'applicationIds': [],
            'resourceIds': role['startingResourceIds'],
            'transducerIds': role['startingTransducerIds'],
            'networkRules': role['networkRules'],
            'state': 'CREATING',
            'ipAddress': 'NULL'
        }
        ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')
        assert self.inst.add_obj(ldap_virtue, 'virtues', 'cid') == 0

        virtue_path = 'images/provisioned_virtues/' + virtue['id'] + '.img'

        try:

            # For now generate keys and store in local dir
            subprocess.check_output(
                shlex.split(('ssh-keygen -t rsa -f {0}/{1}.pem -C'
                             ' "Virtue Key for {1}" -N ""').format(
                                 USER_KEY_DIR, virtue['id'])))

            with open(USER_KEY_DIR + '/' + virtue['id'] + '.pem',
                      'r') as virtue_key_file:
                virtue_key = virtue_key_file.read().strip()
            with open(GALAHAD_KEY_DIR + '/excalibur_pub.pem',
                      'r') as excalibur_key_file:
                excalibur_key = excalibur_key_file.read().strip()

            user_key = subprocess.check_output([
                'ssh-keygen', '-y', '-f',
                '{0}/{1}.pem'.format(USER_KEY_DIR, self.username)
            ])

            with open(GALAHAD_KEY_DIR + '/rethinkdb_cert.pem',
                      'r') as rdb_cert_file:
                rdb_cert = rdb_cert_file.read().strip()

            with open('/tmp/networkRules-' + virtue['id'],
                      'w+') as iprules_file:
                for rule in role['networkRules']:
                    iprules_file.write(rule + '\n')

            # Create the virtue standby image files
            standby_virtues = StandbyVirtues(self.role_id)
            standby_virtues.create_virtue_image_file(self.virtue_id)

            subprocess.check_call(['sudo', 'python',
                                   os.environ['HOME'] + '/galahad/excalibur/'
                                   + \
                                   'call_provisioner.py',
                                   '-u', self.username,
                                   '-i', virtue['id'],
                                   '-n', '/tmp/networkRules-' + virtue['id'],
                                   '-b',
                                   '/mnt/efs/images/non_provisioned_virtues/' +
                                   role['id'] + '.img',
                                   '-o', '/mnt/efs/' + virtue_path,
                                   '-v', virtue_key,
                                   '-e', excalibur_key,
                                   '--user_key', user_key,
                                   '-r', rdb_cert])

            # Enable/disable sensors as specified by the role
            transducers = {}
            for tid in role['startingTransducerIds']:
                transducer = self.inst.get_obj('cid', tid,
                                               'OpenLDAPtransducer', True)
                if (transducer == ()):
                    continue
                ldap_tools.parse_ldap(transducer)
                transducers[tid] = transducer

            eps = EndPoint_Security(self.inst.email, self.inst.password)
            all_transducers = json.loads(eps.transducer_list())
            for transducer in all_transducers:
                if transducer['id'] in transducers:
                    config = transducer['startingConfiguration']
                    ret = eps.transducer_enable(transducer['id'],
                                                self.virtue_id, config)
                else:
                    ret = eps.transducer_disable(transducer['id'],
                                                 self.virtue_id)

            virtue['state'] = 'STOPPED'
            ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')
            assert self.inst.modify_obj('cid', virtue['id'], ldap_virtue) == 0
        except:
            print('Error while creating Virtue for role {0}:\n{1}'.format(
                role['id'], traceback.format_exc()))
            assert self.inst.del_obj('cid',
                                     virtue['id'],
                                     objectClass='OpenLDAPvirtue',
                                     throw_error=True) == 0
            os.remove('{0}/{1}.pem'.format(USER_KEY_DIR, virtue['id']))
            os.remove('{0}/{1}.pem.pub'.format(USER_KEY_DIR, virtue['id']))
            os.remove('/mnt/efs/' + virtue_path)
Exemplo n.º 8
0
    def __init__(self, user, password):
        self.inst = LDAP(user, password)

        self.inst.bind_ldap()
Exemplo n.º 9
0
class EndPoint():
    def __init__(self, user, password):
        self.inst = LDAP(user, password)

        self.inst.bind_ldap()

    # Retrieve information about the specified application
    def application_get(self, username, applicationId):

        try:
            if (not DEBUG_PERMISSIONS):

                user = self.inst.get_obj('cusername', username, 'openLDAPuser')
                if (user == None or user == ()):
                    # User was already validated, but can't be accessed now...
                    return json.dumps(ErrorCodes.user['unspecifiedError'])
                ldap_tools.parse_ldap(user)

            app = self.inst.get_obj('cid', applicationId,
                                    'openLDAPapplication', True)
            if (app == ()):
                return json.dumps(ErrorCodes.user['invalidId'])
            ldap_tools.parse_ldap(app)

            if (DEBUG_PERMISSIONS):
                return json.dumps(app)

            for roleId in user['authorizedRoleIds']:
                role = self.inst.get_obj('cid', roleId, 'openLDAProle')
                if (role == None or role == ()):
                    # Error!
                    continue
                ldap_tools.parse_ldap(role)

                if (applicationId in role['applicationIds']):
                    # User is authorized to access this application.
                    return json.dumps(app)

            return json.dumps(ErrorCodes.user['userNotAuthorized'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Retrieve data about the specified role
    def role_get(self, username, roleId):

        try:
            if (not DEBUG_PERMISSIONS):
                user = self.inst.get_obj('cusername', username, 'openLDAPuser')
                if (user == None or user == ()):
                    return json.dumps(ErrorCodes.user['unspecifiedError'])
                ldap_tools.parse_ldap(user)

            role = self.inst.get_obj('cid', roleId, 'openLDAProle', True)
            if (role == ()):
                return json.dumps(ErrorCodes.user['invalidId'])
            ldap_tools.parse_ldap(role)

            if (DEBUG_PERMISSIONS or roleId in user['authorizedRoleIds']):

                # Now get the IP address of the virtue associated with this user/role
                virtue_ip = 'NULL'

                ldap_virtues = self.inst.get_objs_of_type('OpenLDAPvirtue')
                virtues = ldap_tools.parse_ldap_list(ldap_virtues)

                for v in virtues:
                    if (v['username'] == username and v['roleId'] == roleId):
                        virtue_ip = v['ipAddress']
                        break

                role['ipAddress'] = virtue_ip

                return json.dumps(role)

            return json.dumps(ErrorCodes.user['userNotAuthorized'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Retrieve a list of roles available to user
    def user_role_list(self, username):

        try:
            user = self.inst.get_obj('cusername', username, 'openLDAPuser')
            if (user == None or user == ()):
                return json.dumps(ErrorCodes.user['unspecifiedError'])
            ldap_tools.parse_ldap(user)

            roles = []

            ldap_virtues = self.inst.get_objs_of_type('OpenLDAPvirtue')
            virtues = ldap_tools.parse_ldap_list(ldap_virtues)

            for roleId in user['authorizedRoleIds']:
                role = self.inst.get_obj('cid', roleId, 'openLDAProle')
                if (role == None or role == ()):
                    continue
                ldap_tools.parse_ldap(role)

                # Now get the IP address of the virtue associated with this user/role
                virtue_ip = 'NULL'

                for v in virtues:
                    if (v['username'] == username and v['roleId'] == roleId):
                        virtue_ip = v['ipAddress']
                        break

                role['ipAddress'] = virtue_ip

                roles.append(role)

            return json.dumps(roles)

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Retrieve a list of virtues available to user
    def user_virtue_list(self, username):

        try:
            virtues_raw = self.inst.get_objs_of_type('OpenLDAPvirtue')
            if (virtues_raw == None):
                return json.dumps(ErrorCodes.user['unspecifiedError'])

            virtues_ret = []

            for virtue in virtues_raw:
                ldap_tools.parse_ldap(virtue[1])

                if (virtue[1]['username'] == username):
                    virtues_ret.append(virtue[1])

            return json.dumps(virtues_ret)

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Retrieve information about the specified virtue
    def virtue_get(self, username, virtueId):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.user['invalidId'])
            ldap_tools.parse_ldap(virtue)

            if (virtue['username'] == username or DEBUG_PERMISSIONS):
                return json.dumps(virtue)

            return json.dumps(ErrorCodes.user['userNotAuthorized'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def virtue_reload_state(self, username, virtueId):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.user['invalidId'])
            ldap_tools.parse_ldap(virtue)

            updated_virtue = copy.deepcopy(virtue)

            if (virtue['username'] != username):
                return json.dumps(ErrorCodes.user['userNotAuthorized'])

            rdb_manager = RethinkDbManager()
            rdb_virtue = rdb_manager.get_virtue(virtueId)
            if (rdb_virtue == None):
                updated_virtue['state'] = 'STOPPED'
                updated_virtue['ipAddress'] = 'NULL'
            else:
                updated_virtue['state'] = 'RUNNING'
                updated_virtue['ipAddress'] = rdb_virtue['guestnet']

            if (updated_virtue != virtue):
                ldap_virtue = ldap_tools.to_ldap(updated_virtue, 'OpenLDAPvirtue')
                self.inst.modify_obj('cid', virtueId, ldap_virtue,
                                     'OpenLDAPvirtue', True)

            return json.dumps(ErrorCodes.user['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Launch the specified virtue, which must have already been created
    def virtue_launch(self, username, virtueId, use_valor=True):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.user['invalidId'])
            ldap_tools.parse_ldap(virtue)

            if (virtue['username'] != username):
                return json.dumps(ErrorCodes.user['userNotAuthorized'])

            if ('RUNNING' in virtue['state']
                    or virtue['state'] == 'LAUNCHING'):
                return json.dumps(ErrorCodes.user['virtueAlreadyLaunched'])
            elif (virtue['state'] != 'STOPPED'):
                return json.dumps(
                    ErrorCodes.user['virtueStateCannotBeLaunched'])

            if (use_valor):
                valor_manager = ValorManager()

                valor = valor_manager.get_empty_valor()

                try:
                    virtue['ipAddress'] = valor_manager.add_virtue(
                        valor['address'],
                        valor['valor_id'],
                        virtue['id'],
                        'images/provisioned_virtues/' + virtue['id'] + '.img')

                except AssertionError:
                    return json.dumps(ErrorCodes.user['virtueAlreadyLaunched'])

            virtue['state'] = 'LAUNCHING'
            ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')
            self.inst.modify_obj('cid', virtue['id'], ldap_virtue,
                                 objectClass='OpenLDAPvirtue', throw_error=True)

            # wait until sshable
            success = False
            max_attempts = 5

            # TODO: Remove this variable before merging into master
            see_no_evil = False

            if not use_valor:
                virtue['state'] = 'RUNNING'
            elif see_no_evil:
                virtue['state'] = 'RUNNING (Unverified)'
            else:

                for attempt_number in range(max_attempts):

                    try:

                        time.sleep(30)

                        ssh = ssh_tool(
                            'virtue', virtue['ipAddress'],
                            os.environ['HOME'] + '/user-keys/default-virtue-key.pem')
                        ssh.ssh('echo test')

                        print('Successfully connected to {}'.format(
                            virtue['ipAddress']))

                        # KL --- add if resIDs not empty run:
                        # Kerberos tgt setup for resource management
                        if len(virtue['resourceIds']) is not 0:
                            krb5cc_src = '/tmp/krb5cc_{}'.format(username)
                            krb5cc_dest = '/tmp/krb5cc_0'

                            ssh.scp_to(krb5cc_src, krb5cc_dest)

                            role = self.inst.get_obj('cid', virtue['roleId'], 'openLDAProle')
                            ldap_tools.parse_ldap(role)

                            for res in virtue['resourceIds']:
                                resource = self.inst.get_obj('cid', res, 'openLDAPresource')
                                ldap_tools.parse_ldap(resource)
                                resource_manager = ResourceManager(username, resource)
                                getattr(resource_manager, resource['type'].lower())(
                                    virtue['ipAddress'],
                                    os.environ['HOME'] + '/user-keys/default-virtue-key.pem',
                                    role['applicationIds'])

                        success = True

                        break

                    except Exception as e:
                        print(e)
                        print('Attempt {0} failed to connect').format(attempt_number+1)

                if (not success):
                    valor_manager.rethinkdb_manager.remove_virtue(virtue['id'])
                    virtue['state'] = 'STOPPED'
                    ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')
                    self.inst.modify_obj(
                        'cid', virtue['id'], ldap_virtue,
                        objectClass='OpenLDAPvirtue', throw_error=True)
                    return json.dumps(ErrorCodes.user['serverLaunchError'])

                virtue['state'] = 'RUNNING'

            ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')
            self.inst.modify_obj('cid', virtue['id'], ldap_virtue,
                                 objectClass='OpenLDAPvirtue', throw_error=True)

            return json.dumps(ErrorCodes.user['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Stop the specified virtue, but do not destroy it
    def virtue_stop(self, username, virtueId, use_valor=True):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.user['invalidId'])
            ldap_tools.parse_ldap(virtue)

            if (virtue['username'] != username):
                return json.dumps(ErrorCodes.user['userNotAuthorized'])

            if (virtue['state'] == 'STOPPED'):
                return json.dumps(ErrorCodes.user['virtueAlreadyStopped'])
            elif ('RUNNING' not in virtue['state']):
                return json.dumps(
                    ErrorCodes.user['virtueStateCannotBeStopped'])

            try:
                if (use_valor):

                    if len(virtue['resourceIds']) is not 0:
                        role = self.inst.get_obj('cid', virtue['roleId'], 'openLDAProle')
                        ldap_tools.parse_ldap(role)

                        for res in virtue['resourceIds']:
                            resource = self.inst.get_obj('cid', res, 'openLDAPresource')
                            ldap_tools.parse_ldap(resource)
                            resource_manager = ResourceManager(username, resource)
                            call = 'remove_' + resource['type'].lower()
                            getattr(resource_manager, call)(
                                virtue['ipAddress'],
                                os.environ['HOME'] + '/user-keys/default-virtue-key.pem',
                                role['applicationIds'])

                        ssh = ssh_tool('virtue', virtue['ipAddress'],
                                       os.environ['HOME'] + \
                                       '/user-keys/default-virtue-key.pem')

                        ssh.ssh('sudo rm /tmp/krb5cc_0')

                    rdb_manager = RethinkDbManager()
                    rdb_manager.remove_virtue(virtue['id'])
            except AssertionError:
                return json.dumps(ErrorCodes.user['serverStopError'])
            except:
                print('Error:\n{}'.format(traceback.format_exc()))
                return json.dumps(ErrorCodes.user['unspecifiedError'])
            else:
                virtue['state'] = 'STOPPED'
                ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')
                self.inst.modify_obj(
                    'cid', virtue['id'], ldap_virtue,
                    objectClass='OpenLDAPvirtue', throw_error=True)

            return json.dumps(ErrorCodes.user['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Launch an application on the specified virtue
    def virtue_application_launch(self, username, virtueId, applicationId, use_ssh=True):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.user['invalidVirtueId'])
            ldap_tools.parse_ldap(virtue)

            if (virtue['username'] != username):
                return json.dumps(ErrorCodes.user['userNotAuthorized'])

            if ('RUNNING' not in virtue['state'] and use_ssh):
                return json.dumps(ErrorCodes.user['virtueNotRunning'])

            app = self.inst.get_obj('cid', applicationId,
                                    'OpenLDAPapplication', True)
            if (app == ()):
                return json.dumps(ErrorCodes.user['invalidApplicationId'])
            ldap_tools.parse_ldap(app)

            role = self.inst.get_obj('cid', virtue['roleId'], 'OpenLDAProle')
            if (role == None or role == ()):
                return json.dumps(ErrorCodes.user['unspecifiedError'])
            ldap_tools.parse_ldap(role)

            if (app['id'] not in role['applicationIds']):
                return json.dumps(ErrorCodes.user['applicationNotInVirtue'])

            if (app['id'] in virtue['applicationIds']):
                return json.dumps(
                    ErrorCodes.user['applicationAlreadyLaunched'])

            if (use_ssh):
                ssh = ssh_tool('virtue', virtue['ipAddress'],
                               '{0}/user-keys/{1}.pem'.format(
                                   os.environ['HOME'], username))

                start_docker_container = ('sudo docker start $(sudo docker ps' +
                                          ' -af name="{0}" -q)').format(
                                              app['id'])

                # Copy the network Rules file.
                copy_network_rules = (
                    'sudo docker cp /etc/networkRules $(sudo docker ps -af' +
                    ' name="{0}" -q):/etc/networkRules').format(app['id'])
                ssh.ssh(copy_network_rules)

                # Copy the authorized keys file
                auth_keys_path = '/home/virtue/.ssh/authorized_keys'
                copy_authorized_keys_cmd = (
                    'sudo docker cp {0}'
                    ' {1}:{0}').format(auth_keys_path, app['id'])
                ssh.ssh(copy_authorized_keys_cmd)

                docker_exit = ssh.ssh(start_docker_container,
                                      test=False, silent=True)

                if (docker_exit != 0):
                    # This is an issue with docker where if the docker daemon exits
                    # uncleanly then a system file is locked and docker start fails
                    # with the error:
                    #     Error response from daemon: id already in use
                    #     Error: failed to start containers:
                    # The current workaround is to issue the docker start command
                    # twice. Tne first time it fails with the above error and the
                    # second time it succeeds.
                    docker_exit = ssh.ssh(start_docker_container, test=False)
                if (docker_exit != 0):
                    print(
                        "Docker start command for launching application {} Failed".format(
                            app['id']))
                    return json.dumps(ErrorCodes.user['serverLaunchError'])

                docker_chown_cmd = (
                    'sudo docker exec {0}'
                    ' chown virtue:virtue {1}').format(
                        app['id'], auth_keys_path)
                ssh.ssh(docker_chown_cmd)

                docker_chmod_cmd = (
                    'sudo docker exec {0}'
                    ' which chmod 600 {1}').format(app['id'], auth_keys_path)
                ssh.ssh(docker_chmod_cmd)

            virtue['applicationIds'].append(applicationId)

            del virtue['state']
            del virtue['ipAddress']

            ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')

            assert 0 == self.inst.modify_obj('cid', virtue['id'], ldap_virtue,
                                             objectClass='OpenLDAPvirtue',
                                             throw_error=True)

            return json.dumps(ErrorCodes.user['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Stop an application on the specified virtue
    def virtue_application_stop(self, username, virtueId, applicationId, use_ssh=True):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.user['invalidVirtueId'])
            ldap_tools.parse_ldap(virtue)

            if (virtue['username'] != username):
                return json.dumps(ErrorCodes.user['userNotAuthorized'])

            if ('RUNNING' not in virtue['state'] and use_ssh):
                return json.dumps(ErrorCodes.user['virtueNotRunning'])

            app = self.inst.get_obj('cid', applicationId,
                                    'OpenLDAPapplication', True)
            if (app == ()):
                return json.dumps(ErrorCodes.user['invalidApplicationId'])
            ldap_tools.parse_ldap(app)

            role = self.inst.get_obj('cid', virtue['roleId'], 'OpenLDAProle')
            if (role == None or role == ()):
                return json.dumps(ErrorCodes.user['unspecifiedError'])
            ldap_tools.parse_ldap(role)

            if (app['id'] not in role['applicationIds']):
                return json.dumps(ErrorCodes.user['applicationNotInVirtue'])

            if (app['id'] not in virtue['applicationIds']):
                return json.dumps(ErrorCodes.user['applicationAlreadyStopped'])

            if (use_ssh):
                ssh = ssh_tool('virtue', virtue['ipAddress'],
                               '{0}/user-keys/{1}.pem'.format(
                                   os.environ['HOME'], username))

                docker_exit = ssh.ssh(('sudo docker stop $(sudo docker ps -af '
                                       'name="{0}" -q)').format(app['id']),
                                      test=False)

                if (docker_exit != 0):
                    return json.dumps(ErrorCodes.user['serverStopError'])

            virtue['applicationIds'].remove(applicationId)

            del virtue['state']
            del virtue['ipAddress']

            ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')

            assert 0 == self.inst.modify_obj('cid', virtue['id'], ldap_virtue,
                                             objectClass='OpenLDAPvirtue',
                                             throw_error=True)

            return json.dumps(ErrorCodes.user['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def key_get(self, username):

        try:
            with open('{0}/user-keys/{1}.pem'.format(
                    os.environ['HOME'], username), 'r') as keyfile:
                data = keyfile.read()

            return json.dumps(data)

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])
Exemplo n.º 10
0
    def __init__(self, user, password):

        self.inst = LDAP(user, password)
        self.inst.bind_ldap()
        self.valor_api = ValorAPI()
        self.rdb_manager = RethinkDbManager()
Exemplo n.º 11
0
class EndPoint_Admin():
    def __init__(self, user, password):

        self.inst = LDAP(user, password)
        self.inst.bind_ldap()
        self.valor_api = ValorAPI()
        self.rdb_manager = RethinkDbManager()

    def application_list(self):

        try:
            ldap_applications = self.inst.get_objs_of_type(
                'OpenLDAPapplication')
            assert ldap_applications != None

            applications = ldap_tools.parse_ldap_list(ldap_applications)

            return json.dumps(applications)

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def resource_create(self, resource):
        try:
            resource_keys = ['credentials', 'type', 'unc']
            if (set(resource.keys()) != set(resource_keys)
                    and set(resource.keys()) != set(resource_keys + ['id'])):
                return json.dumps(ErrorCodes.admin['invalidFormat'])
            if (not isinstance(resource['credentials'], basestring)
                    or not isinstance(resource['type'], basestring)
                    or not isinstance(resource['unc'], basestring)):
                return json.dumps(ErrorCodes.admin['invalidFormat'])
            resource['id'] = 'Resource_{}_{}'.format(resource['type'],
                                                     int(time.time()))
            ldap_resource = ldap_tools.to_ldap(resource, 'OpenLDAPresource')
            self.inst.add_obj(ldap_resource,
                              'resources',
                              'cid',
                              throw_error=True)

            return json.dumps(resource)
        except Exception as e:
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def resource_destroy(self, resourceId):
        try:
            resource = self.inst.get_obj('cid', resourceId, 'OpenLDAPresource',
                                         True)
            if (resource == ()):
                return json.dumps(ErrorCodes.admin['invalidId'])
            ldap_tools.parse_ldap(resource)

            # KL --- add check if in use
            ldap_virtues = self.inst.get_objs_of_type('OpenLDAPvirtue')
            virtues = ldap_tools.parse_ldap_list(ldap_virtues)

            if any(resourceId in virtue['resourceIds'] for virtue in virtues):
                return json.dumps(ErrorCodes.admin['virtueUsingResource'])

            self.inst.del_obj('cid', resource['id'], throw_error=True)
        except:
            print('Error while deleting {}:\n{}'.format(
                resource['id'], traceback.format_exc()))
            return json.dumps(ErrorCodes.user['serverDestroyError'])

        return json.dumps(ErrorCodes.admin['success'])

    def resource_get(self, resourceId):

        try:
            resource = self.inst.get_obj('cid',
                                         resourceId,
                                         objectClass='OpenLDAPresource',
                                         throw_error=True)
            if (resource == ()):
                return json.dumps(ErrorCodes.admin['invalidId'])
            ldap_tools.parse_ldap(resource)

            return json.dumps(resource)

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def resource_list(self):

        try:
            ldap_resources = self.inst.get_objs_of_type('OpenLDAPresource')
            assert ldap_resources != None

            resources = ldap_tools.parse_ldap_list(ldap_resources)

            return json.dumps(resources)

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def resource_attach(self, resourceId, virtueId):

        try:
            resource = self.inst.get_obj('cid',
                                         resourceId,
                                         objectClass='OpenLDAPresource',
                                         throw_error=True)
            if (resource == ()):
                return json.dumps(ErrorCodes.admin['invalidResourceId'])
            ldap_tools.parse_ldap(resource)

            virtue = self.inst.get_obj('cid',
                                       virtueId,
                                       objectClass='OpenLDAPvirtue',
                                       throw_error=True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.admin['invalidVirtueId'])
            ldap_tools.parse_ldap(virtue)

            #if (virtue['state'] == 'DELETING'):
            #    return json.dumps(ErrorCodes.admin['invalidVirtueState'])
            if (virtue['state'] != 'STOPPED'):
                return json.dumps(ErrorCodes.admin['invalidVirtueState'])

            if (resourceId in virtue['resourceIds']):
                return json.dumps(ErrorCodes.admin['cantAttach'])

            virtue['resourceIds'].append(resourceId)
            self.inst.modify_obj('cid',
                                 virtue['id'],
                                 ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue'),
                                 objectClass='OpenLDAPvirtue',
                                 throw_error=True)

            #return json.dumps(ErrorCodes.admin['notImplemented'])
            return json.dumps(ErrorCodes.admin['success'])

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def resource_detach(self, resourceId, virtueId):

        try:
            resource = self.inst.get_obj('cid',
                                         resourceId,
                                         objectClass='OpenLDAPresource',
                                         throw_error=True)
            if (resource == ()):
                return json.dumps(ErrorCodes.admin['invalidResourceId'])
            ldap_tools.parse_ldap(resource)

            virtue = self.inst.get_obj('cid',
                                       virtueId,
                                       objectClass='OpenLDAPvirtue',
                                       throw_error=True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.admin['invalidVirtueId'])
            ldap_tools.parse_ldap(virtue)

            if (resourceId not in virtue['resourceIds']):
                return json.dumps(ErrorCodes.admin['cantDetach'])

            if (virtue['state'] != 'STOPPED'):
                return json.dumps(ErrorCodes.admin['invalidVirtueState'])

            virtue['resourceIds'].remove(resourceId)
            self.inst.modify_obj('cid',
                                 virtue['id'],
                                 ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue'),
                                 objectClass='OpenLDAPvirtue',
                                 throw_error=True)

            #return json.dumps(ErrorCodes.admin['notImplemented'])
            return json.dumps(ErrorCodes.admin['success'])
        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def role_create(self, role, use_ssh=True, unity_img_name=None):

        try:
            role_keys = [
                'name', 'version', 'applicationIds', 'startingResourceIds',
                'startingTransducerIds', 'networkRules'
            ]
            if (set(role.keys()) != set(role_keys)
                    and set(role.keys()) != set(role_keys + ['id'])):
                return json.dumps(ErrorCodes.admin['invalidFormat'])

            if (not isinstance(role['name'], basestring)
                    or not isinstance(role['version'], basestring)
                    or type(role['applicationIds']) != list
                    or type(role['startingResourceIds']) != list
                    or type(role['networkRules']) != list
                    or type(role['startingTransducerIds']) != list):
                return json.dumps(ErrorCodes.admin['invalidFormat'])

            if not role['applicationIds']:
                return json.dumps(ErrorCodes.admin['NoApplicationId'])

            default_unity_size = 3  # Measured in GB.

            for a in role['applicationIds']:
                app_test = self.inst.get_obj('cid',
                                             a,
                                             objectClass='OpenLDAPapplication',
                                             throw_error=True)
                if (app_test == ()):
                    return json.dumps(ErrorCodes.admin['invalidApplicationId'])

                ldap_tools.parse_ldap(app_test)

                if (app_test['os'] == 'WINDOWS'):
                    if (app_test['name'].startswith('Microsoft Office')):
                        default_unity_size = default_unity_size + 7
                    else:
                        default_unity_size = default_unity_size + 3
                else:
                    default_unity_size = default_unity_size + 2

            for r in role['startingResourceIds']:
                res_test = self.inst.get_obj('cid',
                                             r,
                                             objectClass='OpenLDAPresource',
                                             throw_error=True)
                if (res_test == ()):
                    return json.dumps(ErrorCodes.admin['invalidResourceId'])

            ldap_transducers = self.inst.get_objs_of_type('OpenLDAPtransducer')
            assert ldap_transducers != None

            all_transducers = ldap_tools.parse_ldap_list(ldap_transducers)

            for t in role['startingTransducerIds']:
                if (t not in [tr['id'] for tr in all_transducers]):
                    return json.dumps(ErrorCodes.admin['invalidTransducerId'])

            new_role = copy.deepcopy(role)

            for t in all_transducers:
                if (t['startEnabled']
                        and t['id'] not in role['startingTransducerIds']):
                    new_role['startingTransducerIds'].append(t['id'])

            new_role['id'] = '{0}{1}'.format(
                new_role['name'].lower().replace(' ', '_'), int(time.time()))

            if (unity_img_name == None):

                closest_fit = 0
                for img in os.listdir('/mnt/efs/images/unities'):
                    img_size = int(img.replace('GB.img', ''))
                    if (img_size >= default_unity_size
                            and (closest_fit == 0 or closest_fit > img_size)):
                        closest_fit = img_size

                if (closest_fit != 0):
                    unity_img_name = '{}GB'.format(closest_fit)
                else:
                    return json.dumps({
                        'status':
                        'failed',
                        'result': [
                            17,
                            ('Could not automatically find a usable unity'
                             ' for this role. Please specify a unity'
                             ' image.')
                        ]
                    })

            if ((unity_img_name + '.img')
                    not in os.listdir('/mnt/efs/images/unities')):
                return json.dumps({
                    'status':
                    'failed',
                    'result': [
                        17, ('Could not find a unity with the name'
                             ' ({})').format(unity_img_name)
                    ]
                })

            try:
                # Call a controller thread to create and assemble the new image
                thr = AssembleRoleThread(self.inst.email,
                                         self.inst.password,
                                         new_role,
                                         unity_img_name,
                                         use_ssh=use_ssh)
            except AssertionError:
                return json.dumps(ErrorCodes.admin['storageError'])
            thr.start()

            return json.dumps({'id': new_role['id'], 'name': new_role['name']})

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    # Destroy the specified role
    def role_destroy(self, roleId, use_nfs=True):

        try:
            role = self.inst.get_obj('cid', roleId, 'OpenLDAProle', True)
            if (role == ()):
                return json.dumps(ErrorCodes.admin['invalidId'])
            ldap_tools.parse_ldap(role)

            # Check if any virtues exist with given role
            virtues = self.inst.get_objs_of_type('OpenLDAPvirtue')
            for virtue in virtues:
                ldap_tools.parse_ldap(virtue[1])
                if (virtue[1]['roleId'] == roleId):
                    # A Virtue exists for this role - Unable to destroy role
                    virtueUsingRoleError = []
                    virtueUsingRoleError.append({
                        'Virtue using the '
                        'specified role exists':
                        virtue[1]['id']
                    })
                    virtueUsingRoleError.append(
                        ErrorCodes.admin['virtueUsingRole'])
                    return json.dumps(virtueUsingRoleError)

            # Check if any user is authorized for the given role
            users = self.inst.get_objs_of_type('OpenLDAPuser')
            for user in users:
                ldap_tools.parse_ldap(user[1])
                if (roleId in user[1]['authorizedRoleIds']):
                    # A User exists with this role authorized - Unable to
                    # destroy role
                    userUsingRoleError = []
                    userUsingRoleError.append({
                        'User authorized for the '
                        'specified role exists':
                        user[1]['username']
                    })
                    userUsingRoleError.append(
                        ErrorCodes.admin['userUsingRole'])
                    return json.dumps(userUsingRoleError)

            try:
                self.inst.del_obj('cid', roleId, throw_error=True)
                if (use_nfs):
                    subprocess.check_call([
                        'sudo', 'rm',
                        '/mnt/efs/images/non_provisioned_virtues/' +
                        role['id'] + '.img'
                    ])

                    # Delete the Standby virtue role image files
                    files = os.listdir('/mnt/efs/images/provisioned_virtues/')
                    standby_files = (file for file in files if role['id'] +
                                     '_STANDBY_VIRTUE_' in file)
                    for standby_file in standby_files:
                        subprocess.check_call([
                            'sudo', 'rm',
                            '/mnt/efs/images/provisioned_virtues/' +
                            standby_file
                        ])
            except:
                print('Error while deleting {0}:\n{1}'.format(
                    role['id'], traceback.format_exc()))
                return json.dumps(ErrorCodes.admin['roleDestroyError'])

            return json.dumps(ErrorCodes.admin['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def role_list(self):

        try:
            ldap_roles = self.inst.get_objs_of_type('OpenLDAProle')
            assert ldap_roles != None

            roles = ldap_tools.parse_ldap_list(ldap_roles)

            return json.dumps(roles)

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def system_export(self):
        return json.dumps(ErrorCodes.admin['notImplemented'])

    def system_import(self, data):
        return json.dumps(ErrorCodes.admin['notImplemented'])

    def test_import_user(self, which):
        return json.dumps(ErrorCodes.admin['notImplemented'])

    def test_import_application(self, which):
        return json.dumps(ErrorCodes.admin['notImplemented'])

    def test_import_role(self, which):
        return json.dumps(ErrorCodes.admin['notImplemented'])

    def user_list(self):

        try:
            # Check AD and update user list in ldap if required
            update_ldap_users_from_ad()

            ldap_users = self.inst.get_objs_of_type('OpenLDAPuser')
            assert ldap_users != None

            users = ldap_tools.parse_ldap_list(ldap_users)

            return json.dumps(users)

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def user_get(self, username):

        try:
            # Check AD and update user list in ldap if required
            update_ldap_users_from_ad()

            user = self.inst.get_obj('cusername',
                                     username,
                                     objectClass='OpenLDAPuser',
                                     throw_error=True)
            if (user == ()):
                return json.dumps(ErrorCodes.admin['invalidUsername'])
            ldap_tools.parse_ldap(user)

            return json.dumps(user)

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def user_virtue_list(self, username):

        try:
            # Check AD and update user list in ldap if required
            update_ldap_users_from_ad()

            user = self.inst.get_obj('cusername',
                                     username,
                                     objectClass='OpenLDAPuser')
            if (user == ()):
                return json.dumps(ErrorCodes.admin['invalidUsername'])
            elif (user == None):
                return json.dumps(ErrorCodes.admin['unspecifiedError'])

            ep = EndPoint(self.inst.email, self.inst.password)

            return ep.user_virtue_list(username)

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def user_role_authorize(self, username, roleId):

        try:
            # Check AD and update user list in ldap if required
            update_ldap_users_from_ad()

            user = self.inst.get_obj('cusername',
                                     username,
                                     objectClass='OpenLDAPuser',
                                     throw_error=True)
            if (user == ()):
                return json.dumps(ErrorCodes.admin['invalidUsername'])
            ldap_tools.parse_ldap(user)

            role = self.inst.get_obj('cid',
                                     roleId,
                                     objectClass='OpenLDAProle',
                                     throw_error=True)
            if (role == ()):
                if (roleId in user['authorizedRoleIds']):
                    # The user is authorized for a nonexistent role...
                    # Remove it from their list?
                    pass
                return json.dumps(ErrorCodes.admin['invalidRoleId'])
            ldap_tools.parse_ldap(role)

            if (roleId in user['authorizedRoleIds']):
                return json.dumps(ErrorCodes.admin['userAlreadyAuthorized'])

            user['authorizedRoleIds'].append(roleId)

            ldap_user = ldap_tools.to_ldap(user, 'OpenLDAPuser')

            self.inst.modify_obj('cusername',
                                 username,
                                 ldap_user,
                                 objectClass='OpenLDAPuser',
                                 throw_error=True)

            return json.dumps(ErrorCodes.admin['success'])

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def user_role_unauthorize(self, username, roleId):

        try:
            user = self.inst.get_obj('cusername',
                                     username,
                                     objectClass='OpenLDAPuser',
                                     throw_error=True)
            if (user == ()):
                return json.dumps(ErrorCodes.admin['invalidUsername'])
            ldap_tools.parse_ldap(user)

            role = self.inst.get_obj('cid',
                                     roleId,
                                     objectClass='OpenLDAProle',
                                     throw_error=True)
            if (roleId not in user['authorizedRoleIds'] and role == ()):
                # If the role does not exist AND the user isn't 'authorized'
                # for it, return error. If the user is not authorized for a
                # real role, return error. If the user is authorized for a
                # nonexistent role, the admin may be trying to clean up an error
                return json.dumps(ErrorCodes.admin['invalidRoleId'])
            elif (roleId not in user['authorizedRoleIds']):
                return json.dumps(ErrorCodes.admin['userNotAlreadyAuthorized'])
            ldap_tools.parse_ldap(role)

            virtues = self.inst.get_objs_of_type('OpenLDAPvirtue')
            for v in virtues:
                ldap_tools.parse_ldap(v[1])

                if (v[1]['username'] == username and v[1]['roleId'] == roleId):
                    # Todo: Check if the user is logged on
                    return json.dumps(ErrorCodes.admin['userUsingVirtue'])

            for r in user['authorizedRoleIds']:
                if (r == roleId):
                    user['authorizedRoleIds'].remove(r)
                    del r

            ldap_user = ldap_tools.to_ldap(user, 'OpenLDAPuser')

            self.inst.modify_obj('cusername',
                                 username,
                                 ldap_user,
                                 objectClass='OpenLDAPuser',
                                 throw_error=True)

            return json.dumps(ErrorCodes.admin['success'])

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    # Create a virtue for the specified role, but do not launch it yet
    def virtue_create(self, username, roleId, use_nfs=True):

        try:
            user = None
            role = None
            resources = []
            virtue_dict = {}

            user = self.inst.get_obj('cusername', username, 'OpenLDAPuser')
            if (user == None or user == ()):
                return json.dumps(ErrorCodes.admin['invalidUsername'])
            ldap_tools.parse_ldap(user)

            role = self.inst.get_obj('cid', roleId, 'OpenLDAProle', True)
            if (role == ()):
                return json.dumps(ErrorCodes.admin['invalidRoleId'])
            ldap_tools.parse_ldap(role)

            if (roleId not in user['authorizedRoleIds']):
                return json.dumps(ErrorCodes.admin['userNotAlreadyAuthorized'])

            if (role.get('state', 'CREATED') != 'CREATED'):
                return json.dumps(ErrorCodes.admin['invalidRoleState'])

            virtue = None
            curr_virtues = self.inst.get_objs_of_type('OpenLDAPvirtue')
            for v in curr_virtues:
                ldap_tools.parse_ldap(v[1])
                if (v[1]['username'] == username and v[1]['roleId'] == roleId):
                    return json.dumps(
                        ErrorCodes.user['virtueAlreadyExistsForRole'])

            for rid in role['startingResourceIds']:

                resource = self.inst.get_obj('cid', rid, 'OpenLDAPresource',
                                             True)
                if (resource == ()):
                    continue
                ldap_tools.parse_ldap(resource)

                resources.append(resource)

            virtue_id = 'Virtue_{0}_{1}'.format(
                role['name'].lower().replace(' ', '_'), int(time.time()))

            thr = CreateVirtueThread(self.inst.email,
                                     self.inst.password,
                                     role['id'],
                                     username,
                                     virtue_id,
                                     role=role)

            if (use_nfs):
                thr.start()
            else:
                virtue = {
                    'id': virtue_id,
                    'username': username,
                    'roleId': roleId,
                    'applicationIds': [],
                    'resourceIds': role['startingResourceIds'],
                    'transducerIds': role['startingTransducerIds'],
                    'networkRules': role['networkRules'],
                    'state': 'STOPPED',
                    'ipAddress': 'NULL'
                }
                ldap_virtue = ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue')
                self.inst.add_obj(ldap_virtue, 'virtues', 'cid')

            # Return the whole thing
            # return json.dumps( virtue )

            # Return a json of the id and ip address
            return json.dumps({'ipAddress': 'NULL', 'id': virtue_id})

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    # Destroy the specified stopped virtue
    def virtue_destroy(self, virtueId, use_nfs=True):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.admin['invalidId'])
            ldap_tools.parse_ldap(virtue)

            if (virtue['state'] != 'STOPPED'):
                return json.dumps(ErrorCodes.user['virtueNotStopped'])

            try:
                if (use_nfs):
                    subprocess.check_call([
                        'sudo', 'rm', '/mnt/efs/images/provisioned_virtues/' +
                        virtue['id'] + '.img'
                    ])
                self.inst.del_obj('cid', virtue['id'], throw_error=True)
            except:
                print('Error while deleting {0}:\n{1}'.format(
                    virtue['id'], traceback.format_exc()))
                return json.dumps(ErrorCodes.user['serverDestroyError'])

            self.rdb_manager.destroy_virtue(virtue['id'])

            return json.dumps(ErrorCodes.admin['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def virtue_reload_state(self, virtueId):

        try:
            virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
            if (virtue == ()):
                return json.dumps(ErrorCodes.user['invalidId'])
            ldap_tools.parse_ldap(virtue)

            updated_virtue = copy.deepcopy(virtue)

            rdb_manager = RethinkDbManager()
            rdb_virtue = rdb_manager.get_virtue(virtueId)
            if (rdb_virtue == None):
                updated_virtue['state'] = 'STOPPED'
                updated_virtue['ipAddress'] = 'NULL'
            else:
                updated_virtue['state'] = 'RUNNING'
                updated_virtue['ipAddress'] = rdb_virtue['guestnet']

            if (updated_virtue != virtue):
                ldap_virtue = ldap_tools.to_ldap(updated_virtue,
                                                 'OpenLDAPvirtue')
                self.inst.modify_obj('cid', virtueId, ldap_virtue,
                                     'OpenLDAPvirtue', True)

            return json.dumps(ErrorCodes.user['success'])

        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def valor_create(self):

        try:

            valor_id = self.valor_api.valor_create()

            return json.dumps({'valor_id': valor_id})

        except:

            print('Error:\n{0}'.format(traceback.format_exc()))

            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def valor_launch(self, valor_id):

        try:

            valor_id = self.valor_api.valor_launch(valor_id)

            return json.dumps({'valor_id': valor_id})

        except:

            print('Error:\n{0}'.format(traceback.format_exc()))

            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def valor_stop(self, valor_id):

        try:

            valor_id = self.valor_api.valor_stop(valor_id)

            return json.dumps({'valor_id': valor_id})

        except Exception as exception:

            print('Error:\n{0}'.format(traceback.format_exc()))

            # Virtue/s exists on this valor - Unable to stop valor
            return json.dumps({
                'status': 'failed',
                'result': [11, exception.message]
            })

    def valor_destroy(self, valor_id):

        try:

            valor_id = self.valor_api.valor_destroy(valor_id)

            return json.dumps({'valor_id': valor_id})

        except Exception as exception:

            print('Error:\n{0}'.format(traceback.format_exc()))

            # Virtue/s exists on this valor - Unable to destroy valor
            return json.dumps({
                'status': 'failed',
                'result': [11, exception.message]
            })

    def valor_list(self):

        try:

            valors = self.valor_api.valor_list()

            return json.dumps(valors)

        except:

            print('Error:\n{0}'.format(traceback.format_exc()))

            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def valor_create_pool(self, number_of_valors):

        try:

            valor_ids = self.valor_api.valor_create_pool(number_of_valors)

            return json.dumps({'valor_ids': valor_ids})

        except:

            print('Error:\n{0}'.format(traceback.format_exc()))

            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def valor_migrate_virtue(self, virtue_id, destination_valor_id):

        try:

            valor_id = self.valor_api.valor_migrate_virtue(
                virtue_id, destination_valor_id)

            return json.dumps({'valor_id': valor_id})

        except Exception as exception:

            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps({
                'status': 'failed',
                'result': [11, exception.message]
            })

    def galahad_get_id(self):

        try:

            instance_data = AWS.get_instance_info()
            return json.dumps(instance_data['instance-id'])

        except Exception as e:

            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def application_add(self, application):

        try:

            app = copy.copy(application)

            if (set(app.keys()) != set(['id', 'name', 'version', 'os'])
                    and set(app.keys()) != set(
                        ['id', 'name', 'version', 'os', 'port'])):
                return json.dumps(ErrorCodes.admin['invalidFormat'])

            if (isinstance(app.get('port'), basestring)):
                app['port'] = int(app['port'])

            if (not isinstance(app['id'], basestring)
                    or not isinstance(app['name'], basestring)
                    or not isinstance(app['version'], basestring)
                    or type(app.get('port', 0)) != int):
                return json.dumps(ErrorCodes.admin['invalidFormat'])

            if (app['os'] != 'LINUX' and app['os'] != 'WINDOWS'):
                return json.dumps(ErrorCodes.admin['invalidFormat'])

            if (self.inst.get_obj('cid', app['id'], throw_error=True) != ()):
                return json.dumps(ErrorCodes.admin['invalidId'])

            ecr_auth_json = subprocess.check_output([
                'aws', 'ecr', 'get-authorization-token', '--registry-ids',
                '703915126451', '--output', 'json', '--region', 'us-east-2'
            ])

            ecr_auth = json.loads(ecr_auth_json.decode())

            docker_registry = ecr_auth['authorizationData'][0]['proxyEndpoint']
            docker_token = ecr_auth['authorizationData'][0][
                'authorizationToken']

            # Since the user is only adding the app, not creating it, make sure
            # the image is already in the docker repo.
            response = requests.get(
                '{0}/v2/starlab-virtue/tags/list'.format(docker_registry),
                headers={'Authorization': 'Basic ' + docker_token})

            if ('virtue-' + app['id'] not in response.json()['tags']):
                return json.dumps(ErrorCodes.admin['imageNotFound'])

            ldap_app = ldap_tools.to_ldap(app, 'OpenLDAPapplication')
            ret = self.inst.add_obj(ldap_app, 'virtues', 'cid')
            assert ret == 0

            return json.dumps(ErrorCodes.admin['success'])

        except Exception as e:

            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])

    def auto_migration_start(self, migration_interval=None):
        try:
            self.valor_api.auto_migration_start(migration_interval)
            return json.dumps(ErrorCodes.admin['success'])
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def auto_migration_stop(self):
        try:
            self.valor_api.auto_migration_stop()
            return json.dumps(ErrorCodes.admin['success'])
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def auto_migration_status(self):
        try:
            status, interval = self.valor_api.auto_migration_status()
            if status:
                migration_status = 'ON'
                return json.dumps({
                    'auto_migration_status': migration_status,
                    'auto_migration_interval': interval
                })
            else:
                migration_status = 'OFF'
                return json.dumps({'auto_migration_status': migration_status})
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def virtue_introspect_start(self, virtue_id, interval=None, modules=None):
        try:
            self.rdb_manager.introspect_virtue_start(virtue_id, interval,
                                                     modules)
            return json.dumps({'virtue_id': virtue_id})
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def virtue_introspect_stop(self, virtue_id):
        try:
            self.rdb_manager.introspect_virtue_stop(virtue_id)
            return json.dumps({'virtue_id': virtue_id})
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def virtue_introspect_start_all(self, interval=None, modules=None):
        try:
            virtues_raw = self.inst.get_objs_of_type('OpenLDAPvirtue')
            if (virtues_raw == None):
                return json.dumps(ErrorCodes.user['unspecifiedError'])

            for virtue in virtues_raw:
                ldap_tools.parse_ldap(virtue[1])
                virtue_running = (virtue[1]['state'] == 'RUNNING')
                if virtue_running:
                    self.rdb_manager.introspect_virtue_start(
                        virtue[1]['id'], interval, modules)

            return json.dumps(ErrorCodes.admin['success'])
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def virtue_introspect_stop_all(self):
        try:
            virtues_raw = self.inst.get_objs_of_type('OpenLDAPvirtue')
            if (virtues_raw == None):
                return json.dumps(ErrorCodes.user['unspecifiedError'])

            for virtue in virtues_raw:
                ldap_tools.parse_ldap(virtue[1])
                virtue_running = (virtue[1]['state'] == 'RUNNING')
                if virtue_running:
                    self.rdb_manager.introspect_virtue_stop(virtue[1]['id'])

            return json.dumps(ErrorCodes.admin['success'])
        except:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.user['unspecifiedError'])

    def _set_introspection_ldap(self, virtueId, isEnabled):
        introsection_id = 'introspection'
        virtue = self.inst.get_obj('cid', virtueId, 'OpenLDAPvirtue', True)
        if virtue is None or virtue == ():
            return json.dumps(ErrorCodes.admin['invalidVirtueId'])

        ldap_tools.parse_ldap(virtue)

        new_t_list = json.loads(virtue['transducerIds'])

        if isEnabled:
            if introsection_id not in new_t_list:
                new_t_list.append(introsection_id)
        else:
            if introsection_id in new_t_list:
                new_t_list.remove(introsection_id)

        virtue['transducerIds'] = json.dumps(new_t_list)
        ret = self.inst.modify_obj(
            'cid', virtueId, ldap_tools.to_ldap(virtue, 'OpenLDAPvirtue'),
            'OpenLDAPvirtue', True)
        if ret != 0:
            return json.dumps(ErrorCodes.user['unspecifiedError'])

        return json.dumps(ErrorCodes.admin['success'])

    def _set_introspection_role(self, isEnabled):
        introspection_id = 'introspection'
        try:
            ldap_roles = self.inst.get_objs_of_type('OpenLDAProle')
            assert ldap_roles != None

            roles = ldap_tools.parse_ldap_list(ldap_roles)

            for role in roles:
                print(role)
                print(role['startingTransducerIds'])
                new_t_list = role['startingTransducerIds']

                if isEnabled:
                    if introspection_id not in new_t_list:
                        new_t_list.append(introspection_id)
                else:
                    if introspection_id in new_t_list:
                        new_t_list.remove(introspection_id)

                role['startingTransducerIds'] = new_t_list
                ret = self.inst.modify_obj(
                    'cid', role['id'],
                    ldap_tools.to_ldap(role,
                                       'OpenLDAProle'), 'OpenLDAProle', True)
                if ret != 0:
                    return json.dumps(ErrorCodes.user['unspecifiedError'])

            return True

        except Exception as e:
            print('Error:\n{0}'.format(traceback.format_exc()))
            return json.dumps(ErrorCodes.admin['unspecifiedError'])