Example #1
0
def delete_host(message, bus):
    """
    Deletes an existing host.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        address = message['params']['address']
        LOGGER.debug('Attempting to delete host "{}"'.format(address))
        bus.request('storage.delete', params=['Host', {'address': address}])
        # TODO: kick off service job to remove the host?

        # Remove from a cluster
        for cluster in bus.request('storage.list', params=['Clusters',
                                                           True])['result']:
            if address in cluster['hostset']:
                LOGGER.info('Removing host "{}" from cluster "{}"'.format(
                    address, cluster['name']))
                cluster['hostset'].pop(cluster['hostset'].index(address))
                bus.request('storage.save', params=['Cluster', cluster])
                # A host can only be part of one cluster so break the loop
                break
        return create_response(message['id'], [])
    except _bus.RemoteProcedureCallError as error:
        LOGGER.debug('Error deleting host: {}: {}'.format(type(error), error))
        return return_error(message, error, JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error deleting host: {}: {}'.format(type(error), error))
        return return_error(message, error, JSONRPC_ERRORS['INTERNAL_ERROR'])
Example #2
0
def delete_network(message, bus):
    """
    Deletes an exisiting network.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        LOGGER.debug('Attempting to delete network "{}"'.format(
            message['params']['name']))
        bus.request('storage.delete',
                    params=['Network', {
                        'name': message['params']['name']
                    }])
        return create_response(message['id'], [])
    except _bus.RemoteProcedureCallError as error:
        LOGGER.debug('Error deleting network: {}: {}'.format(
            type(error), error))
        return return_error(message, error, JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error deleting network: {}: {}'.format(
            type(error), error))
        return return_error(message, error, JSONRPC_ERRORS['INTERNAL_ERROR'])
Example #3
0
def create_network(message, bus):
    """
    Creates a new network.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        LOGGER.debug('create_network params: {}'.format(message['params']))
        # Check to see if we already have a network with that name
        network = bus.request(
            'storage.get',
            params=['Network', {
                'name': message['params']['name']
            }])
        LOGGER.debug(
            'Creation of already exisiting network "{0}" requested.'.format(
                message['params']['name']))

        # If they are the same thing then go ahead and return success
        if models.Network.new(
                **network['result']).to_dict() == models.Network.new(
                    **message['params']).to_dict():
            return create_response(message['id'], network['result'])

        # Otherwise error with a CONFLICT
        return return_error(message,
                            'A network with that name already exists.',
                            JSONRPC_ERRORS['CONFLICT'])
    except _bus.RemoteProcedureCallError as error:
        LOGGER.debug('Error getting network: {}: {}'.format(
            type(error), error))
        LOGGER.info('Attempting to create new network: "{}"'.format(
            message['params']))

    # Create the new network
    try:
        network = models.Network.new(**message['params'])
        network._validate()
        response = bus.request('storage.save',
                               params=['Network', network.to_dict()])
        return create_response(message['id'], response['result'])
    except models.ValidationError as error:
        return return_error(message, error, JSONRPC_ERRORS['INVALID_REQUEST'])
Example #4
0
def update_cluster_members(message, bus):
    """
    Updates the list of members in a cluster.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        old_hosts = set(message['params']['old'])  # Ensures no duplicates
        new_hosts = set(message['params']['new'])  # Ensures no duplicates
        LOGGER.debug('old_hosts="{}", new_hosts="{}"'.format(
            old_hosts, new_hosts))
    except Exception as error:
        return return_error(message, error, JSONRPC_ERRORS['BAD_REQUEST'])

    try:
        cluster = bus.request(
            'storage.get',
            params=['Cluster', {
                'name': message['params']['name']
            }, True])
    except Exception as error:
        return return_error(message, error, JSONRPC_ERRORS['NOT_FOUND'])

    if old_hosts != set(cluster['result']['hostset']):
        msg = 'Conflict setting hosts for cluster {0}'.format(
            cluster['result']['name'])
        LOGGER.error(msg)
        return return_error(message, msg, JSONRPC_ERRORS['CONFLICT'])

    # FIXME: Need input validation.  For each new host,
    #        - Does the host exist at /commissaire/hosts/{IP}?
    #        - Does the host already belong to another cluster?

    # FIXME: Should guard against races here, since we're fetching
    #        the cluster record and writing it back with some parts
    #        unmodified.  Use either locking or a conditional write
    #        with the etcd 'modifiedIndex'.  Deferring for now.
    cluster['result']['hostset'] = list(new_hosts)
    cluster = models.Cluster.new(**cluster['result'])
    cluster._validate()
    response = bus.request('storage.save',
                           params=['Cluster', cluster.to_dict()])
    return create_response(message['id'], response['result'])
Example #5
0
def get_hostcreds(message, bus):
    """
    Gets credentials for a host.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        host_response = bus.request(
            'storage.get',
            params=['Host', {
                'address': message['params']['address']
            }, True])
        creds = {
            'remote_user': host_response['result']['remote_user'],
            'ssh_priv_key': host_response['result']['ssh_priv_key']
        }
        return create_response(message['id'], creds)
    except _bus.RemoteProcedureCallError as error:
        LOGGER.debug('Client requested a non-existant host: "{}"'.format(
            message['params']['address']))
        return return_error(message, error, JSONRPC_ERRORS['NOT_FOUND'])
Example #6
0
 def test_return_error(self):
     """
     Ensure return_error returns a proper error structure.
     """
     result = handlers.return_error({'id': UID}, Exception('test'), 1)
     self.assertEquals(1, result['error']['code'])
     self.assertEquals('test', result['error']['message'])
     self.assertEquals(str(Exception), result['error']['data']['exception'])
Example #7
0
def get_host_status(message, bus):
    """
    Gets the status of an exisiting host.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        host_response = bus.request(
            'storage.get',
            params=['Host', {
                'address': message['params']['address']
            }])
        host = models.Host.new(**host_response['result'])
        status = models.HostStatus.new(
            host={
                'last_check': host.last_check,
                'status': host.status,
            },
            # TODO: Update when we add other types.
            type=C.CLUSTER_TYPE_HOST)

        LOGGER.debug('Status for host "{0}": "{1}"'.format(
            host.address, status.to_json()))

        return create_response(message['id'], status.to_dict())
    except _bus.RemoteProcedureCallError as error:
        LOGGER.warn('Could not retrieve host "{}". {}: {}'.format(
            message['params']['address'], type(error), error))
        return return_error(message, error, JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Host Status exception caught for {0}: {1}:{2}'.format(
            host.address, type(error), error))
        return return_error(message, error, JSONRPC_ERRORS['INTERNAL_ERROR'])
Example #8
0
def create_cluster(message, bus):
    """
    Creates a new cluster.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        bus.request('storage.get',
                    params=['Cluster', {
                        'name': message['params']['name']
                    }])
        LOGGER.debug(
            'Creation of already exisiting cluster {0} requested.'.format(
                message['params']['name']))
    except Exception as error:
        LOGGER.debug('Brand new cluster being created.')

        if message['params'].get('network'):
            # Verify the networks existence
            try:
                bus.request(
                    'storage.get',
                    params=['Network', {
                        'name': message['params']['network']
                    }])
            except Exception as error:
                # Default if the network doesn't exist
                message['params']['network'] = C.DEFAULT_CLUSTER_NETWORK_JSON[
                    'name']  # noqa

    try:
        cluster = models.Cluster.new(**message['params'])
        cluster._validate()
        response = bus.request('storage.save',
                               params=['Cluster', cluster.to_dict()])
        return create_response(message['id'], response['result'])
    except models.ValidationError as error:
        return return_error(message, error, JSONRPC_ERRORS['INVALID_REQUEST'])
Example #9
0
def list_cluster_members(message, bus):
    """
    Lists hosts in a cluster.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    response = None
    try:
        cluster = bus.request('storage.get', params=[
            'Cluster', {'name': message['params']['name']}, True])
        LOGGER.debug('Cluster found: {}'.format(cluster['result']['name']))
        LOGGER.debug('Returning: {}'.format(response))
        return create_response(
            message['id'], result=cluster['result']['hostset'])
    except Exception as error:
        return return_error(message, error, JSONRPC_ERRORS['NOT_FOUND'])
Example #10
0
def get_network(message, bus):
    """
    Gets a specific network.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    try:
        network_response = bus.request(
            'storage.get',
            params=['Network', {
                'name': message['params']['name']
            }, True])
        network = models.Network.new(**network_response['result'])

        return create_response(message['id'], network.to_dict())
    except _bus.RemoteProcedureCallError as error:
        return return_error(message, error, JSONRPC_ERRORS['NOT_FOUND'])
Example #11
0
def create_host(message, bus):
    """
    Creates a new host.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    LOGGER.debug('create_host params: "{}"'.format(message['params']))
    try:
        address = message['params']['address']
    except KeyError:
        return return_error(
            message, '"address" must be given in the url or in the PUT body',
            JSONRPC_ERRORS['INVALID_PARAMETERS'])
    try:
        host = bus.request('storage.get', params=[
            'Host', {'address': address}, True])
        LOGGER.debug('Host "{}" already exisits.'.format(address))

        # Verify the keys match
        if (host['result']['ssh_priv_key'] !=
                message['params'].get('ssh_priv_key', '')):
            return return_error(
                message, 'Host already exists', JSONRPC_ERRORS['CONFLICT'])

        # Verify the cluster exists and it's in the cluster
        if message['params'].get('cluster'):
            cluster = _does_cluster_exist(bus, message['params']['cluster'])
            if not cluster:
                return return_error(
                    message, 'Cluster does not exist',
                    JSONRPC_ERRORS['INVALID_PARAMETERS'])
            # Verify the host is in the cluster
            if address not in cluster.hostset:
                LOGGER.debug('Host "{}" is not in cluster "{}"'.format(
                    address, message['params']['cluster']))
                return return_error(
                    message, 'Host not in cluster', JSONRPC_ERRORS['CONFLICT'])

        # Return out now. No more processing needed.
        return create_response(
            message['id'], models.Host.new(**host['result']).to_dict())

    except _bus.RemoteProcedureCallError as error:
        LOGGER.debug('Brand new host "{}" being created.'.format(
            message['params']['address']))

    if message['params'].get('cluster'):
        # Verify the cluster existence and add the host to it
        cluster_name = message['params']['cluster']
        cluster = _does_cluster_exist(bus, message['params']['cluster'])
        if not cluster:
            LOGGER.warn(
                'create_host could not find cluster "{}" for the creation '
                'of new host "{}"'.format(cluster_name, address))
            return return_error(
                message,
                'Cluster does not exist',
                JSONRPC_ERRORS['INVALID_PARAMETERS'])

        LOGGER.debug('Found cluster. Data: "{}"'.format(cluster))
        if address not in cluster.hostset:
            cluster.hostset.append(address)
            bus.request('storage.save', params=[
                'Cluster', cluster.to_dict(True)])

    try:
        # TODO: pass this off to the bootstrap process
        host = models.Host.new(**message['params'])
        host._validate()
        bus.request(
            'storage.save', params=[
                'Host', host.to_dict(True)])
        return create_response(message['id'], host.to_dict())
    except models.ValidationError as error:
        return return_error(message, error, JSONRPC_ERRORS['INVALID_REQUEST'])