Beispiel #1
0
def delete_cluster_member(message, bus):
    """
    Deletes a member from the 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:
        cluster = bus.request(
            'storage.get',
            params=['Cluster', {
                'name': message['params']['name']
            }, True])
        if message['params']['host'] in cluster['result']['hostset']:
            # 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.
            idx = cluster['result']['hostset'].index(message['params']['host'])
            cluster['result']['hostset'].pop(idx)
            bus.request('storage.save',
                        params=['Cluster', cluster['result'], True])
        return create_response(message['id'], [])
    except Exception as error:
        return create_response(message['id'],
                               error=error,
                               error_code=JSONRPC_ERRORS['NOT_FOUND'])
Beispiel #2
0
def check_cluster_member(message, bus):
    """
    Checks is a member is part of the 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:
        cluster = bus.request(
            'storage.get',
            params=['Cluster', {
                'name': message['params']['name']
            }, True])
        if message['params']['host'] in cluster['result']['hostset']:
            # Return back the host in a list
            return create_response(message['id'], [message['params']['host']])
        else:
            return create_response(
                message['id'],
                error='The requested host is not part of the cluster.',
                error_code=JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        return create_response(message['id'],
                               error=error,
                               error_code=JSONRPC_ERRORS['INTERNAL_ERROR'])
Beispiel #3
0
def add_cluster_member(message, bus):
    """
    Adds a member to the 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:
        cluster = bus.request('storage.get', params=[
            'Cluster', {'name': message['params']['name']}, True])

        if message['params']['host'] not in cluster['result']['hostset']:
            # FIXME: Need input validation.
            #        - 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'].append(message['params']['host'])
            bus.request('storage.save', params=[
                'Cluster', cluster['result'], True])

        # Return back the host in a list
        return create_response(message['id'], [message['params']['host']])
    except Exception as error:
        return create_response(
            message['id'],
            error=error,
            error_code=JSONRPC_ERRORS['INTERNAL_ERROR'])
Beispiel #4
0
 def test_get_network(self):
     """
     Verify get_network responds with the right information.
     """
     bus = mock.MagicMock()
     bus.request.return_value = create_response(ID, NETWORK.to_dict())
     self.assertEquals(create_response(ID, NETWORK.to_dict()),
                       networks.get_network(SIMPLE_NETWORK_REQUEST, bus))
 def test_get_host(self):
     """
     Verify get_host responds with the right information.
     """
     bus = mock.MagicMock()
     bus.request.return_value = create_response(ID, HOST.to_dict())
     self.assertEquals(
         create_response(ID, HOST.to_dict()),
         hosts.get_host(SIMPLE_HOST_REQUEST, bus))
 def test_list_clusters(self):
     """
     Verify list_clusters responds with the right information.
     """
     bus = mock.MagicMock()
     bus.request.return_value = create_response(ID, [{'name': 'test'}])
     self.assertEquals(
         create_response(ID, [CLUSTER.name]),
         clusters.list_clusters(bus.request.return_value, bus))
 def test_get_host_creds(self):
     """
     Verify get_hostcreds responds with the right information.
     """
     bus = mock.MagicMock()
     bus.request.return_value = create_response(ID, HOST.to_dict(True))
     self.assertEquals(
         create_response(ID, {'ssh_priv_key': '', 'remote_user': '******'}),
         hosts.get_hostcreds(SIMPLE_HOST_REQUEST, bus))
    def test_create_cluster(self):
        """
        Verify create_cluster saves new clusters.
        """
        bus = mock.MagicMock()
        cluster_json = Cluster.new(name='test').to_json()
        bus.request.return_value = create_response(ID, cluster_json)

        self.assertEquals(create_response(ID, cluster_json),
                          clusters.create_cluster(SIMPLE_CLUSTER_REQUEST, bus))
 def test_get_host_status(self):
     """
     Verify get_host_status responds with status information.
     """
     bus = mock.MagicMock()
     bus.request.return_value = create_response(ID, HOST.to_dict())
     host_status = HostStatus.new(
         host={'last_check': '', 'status': ''}, type=C.CLUSTER_TYPE_HOST)
     self.assertEquals(
         create_response(ID, host_status.to_dict()),
         hosts.get_host_status(SIMPLE_HOST_REQUEST, bus))
    def test_delete_cluster_member_with_valid_member(self):
        """
        Verify that delete_cluster_member actually removes a member.
        """
        bus = mock.MagicMock()
        cluster = Cluster.new(name='test', hostset=['127.0.0.1'])

        bus.request.return_value = create_response(ID, cluster.to_dict(True))
        self.assertEquals(
            create_response(ID, []),
            clusters.delete_cluster_member(CHECK_CLUSTER_REQUEST, bus))
Beispiel #11
0
 def test_create_network_idempotent(self):
     """
     Verify create_network acts idempotent.
     """
     bus = mock.MagicMock()
     bus.request.side_effect = (
         # Network exists
         create_response(ID, NETWORK.to_dict()),
         # Creation response
         create_response(ID, NETWORK.to_dict()))
     self.assertEquals(create_response(ID, NETWORK.to_dict()),
                       networks.create_network(SIMPLE_NETWORK_REQUEST, bus))
    def test_check_cluster_member_with_valid_member(self):
        """
        Verify that check_cluster_member returns proper data when a valid member is requested.
        """
        bus = mock.MagicMock()
        cluster = Cluster.new(name='test', hostset=['127.0.0.1'])

        bus.request.return_value = create_response(ID, cluster.to_dict(True))

        self.assertEquals(
            create_response(ID, ['127.0.0.1']),
            clusters.check_cluster_member(CHECK_CLUSTER_REQUEST, bus))
    def test_add_cluster_member_with_valid_member(self):
        """
        Verify that add_cluster_member actually adds a new member..
        """
        bus = mock.MagicMock()
        cluster = Cluster.new(name='test', hostset=[])

        bus.request.return_value = create_response(ID, cluster.to_dict(True))
        expected_response = create_response(ID, ['127.0.0.1'])
        self.assertEquals(
            expected_response,
            clusters.add_cluster_member(CHECK_CLUSTER_REQUEST, bus))
Beispiel #14
0
 def test_create_network(self):
     """
     Verify create_network can create a new network.
     """
     bus = mock.MagicMock()
     bus.request.side_effect = (
         # Network doesn't yet exist
         _bus.RemoteProcedureCallError('test'),
         # Creation response
         create_response(ID, NETWORK.to_dict()))
     self.assertEquals(create_response(ID, NETWORK.to_dict()),
                       networks.create_network(SIMPLE_NETWORK_REQUEST, bus))
    def test_create_host(self):
        """
        Verify create_host saves new hosts.
        """
        bus = mock.MagicMock()
        bus.request.side_effect = (
            # Host doesn't exist yet
            _bus.RemoteProcedureCallError('test'),
            # Result from save
            create_response(ID, HOST.to_dict())
        )

        self.assertEquals(
            create_response(ID, HOST.to_dict()),
            hosts.create_host(SIMPLE_HOST_REQUEST, bus))
    def test_create_host_with_the_same_existing_host(self):
        """
        Verify create_host succeeds when a new host matches an existing one.
        """
        bus = mock.MagicMock()
        bus.request.side_effect = (
            # Existing host
            create_response(ID, HOST.to_dict(True)),
            # Result from save
            create_response(ID, HOST.to_dict())
        )

        self.assertEquals(
            create_response(ID, HOST.to_dict()),
            hosts.create_host(SIMPLE_HOST_REQUEST, bus))
Beispiel #17
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'])
Beispiel #18
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'])
Beispiel #19
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'])
Beispiel #20
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'])
Beispiel #21
0
def get_cluster(message, bus):
    """
    Gets a specific 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
    """
    cluster_response = bus.request(
        'storage.get',
        params=['Cluster', {
            'name': message['params']['name']
        }, True])
    cluster = models.Cluster.new(**cluster_response['result'])
    hosts_response = bus.request('storage.list', params=['Hosts'])

    available = unavailable = total = 0

    for host in hosts_response['result']:
        if host['address'] in cluster.hostset:
            total += 1
            if host['status'] == 'active':
                available += 1
            else:
                unavailable += 1

    cluster.hosts['total'] = total
    cluster.hosts['available'] = available
    cluster.hosts['unavailable'] = unavailable

    return create_response(message['id'], cluster.to_dict_with_hosts())
Beispiel #22
0
 def test_create_response_with_result(self):
     """
     Verify create_response creates the proper result jsonrpc structure.
     """
     response = handlers.create_response(UID, result={'test': 'data'})
     self.assertEquals('2.0', response['jsonrpc'])
     self.assertEquals(UID, response['id'])
     self.assertEquals({'test': 'data'}, response['result'])
    def test_create_host_with_existing_host_different_cluster_memebership(self):
        """
        Verify create_host returns conflict existing cluster memebership does not match.
        """
        bus = mock.MagicMock()
        different = HOST.to_dict()
        different['ssh_priv_key'] = ''

        bus.request.side_effect = (
            # Existing host
            create_response(ID, different),
            # Cluster
            create_response(ID, {'hostset': []}),
            create_response(ID, {'hostset': []})
        )

        self.assertEquals(
            expected_error(ID, JSONRPC_ERRORS['CONFLICT']),
            hosts.create_host(CLUSTER_HOST_REQUEST, bus))
 def test_delete_cluster(self):
     """
     Verify delete_cluster deletes existing clusters.
     """
     bus = mock.MagicMock()
     bus.request.side_effect = (
         # The delete shouldn't return anything
         None, )
     self.assertEquals(create_response(ID, []),
                       clusters.delete_cluster(SIMPLE_CLUSTER_REQUEST, bus))
    def test_create_host_with_cluster(self):
        """
        Verify create_host saves new hosts with it's cluster.
        """
        bus = mock.MagicMock()

        bus.request.side_effect = (
            # Host doesn't exist yet
            _bus.RemoteProcedureCallError('test'),
            # Request the cluster
            create_response(ID, {'hostset': []}),
            # Save of the cluster
            create_response(ID, {'hostset': []}),
            # Result from save (ignored)
            create_response(ID, HOST.to_dict())
        )

        self.assertEquals(
            create_response(ID, HOST.to_dict()),
            hosts.create_host(CLUSTER_HOST_REQUEST, bus))
 def test_list_hosts(self):
     """
     Verify list_hosts responds with the right information.
     """
     bus = mock.MagicMock()
     bus.request.return_value = {
         'jsonrpc': '2.0',
         'result': [HOST.to_dict()],
         'id': '123'}
     self.assertEquals(
         create_response(ID, [HOST.to_dict()]),
         hosts.list_hosts(SIMPLE_HOST_REQUEST, bus))
    def test_create_host_with_existing_host_different_ssh_key(self):
        """
        Verify create_host returns conflict existing hosts ssh keys do not match.
        """
        bus = mock.MagicMock()
        different = HOST.to_dict()
        different['ssh_priv_key'] = 'aaa'

        bus.request.return_value = create_response(ID, different)

        self.assertEquals(
            expected_error(ID, JSONRPC_ERRORS['CONFLICT']),
            hosts.create_host(SIMPLE_HOST_REQUEST, bus))
Beispiel #28
0
 def test_create_response_with_error(self):
     """
     Verify create_response creates the proper error jsonrpc structure.
     """
     for (error, expected_response) in [
         (Exception('test'), 'test'),
         ('test', 'test')
     ]:
         response = handlers.create_response(UID, error=error)
         self.assertEquals('2.0', response['jsonrpc'])
         self.assertEquals(UID, response['id'])
         print(response)
         self.assertEquals(expected_response, response['error']['message'])
Beispiel #29
0
 def test_list_networks(self):
     """
     Verify list_networks responds with the right information.
     """
     bus = mock.MagicMock()
     bus.request.return_value = {
         'jsonrpc': '2.0',
         'result': [NETWORK.to_dict()],
         'id': '123'
     }
     self.assertEquals(
         create_response(ID, ['test']),
         clusters.list_clusters(bus.request.return_value, bus))
Beispiel #30
0
def list_hosts(message, bus):
    """
    Lists all hosts.

    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :rtype: dict
    """
    hosts_msg = bus.request('storage.list', params=['Hosts'])
    return create_response(message['id'], hosts_msg['result'])