コード例 #1
0
def get_cluster_deploy(message, bus):
    """
    Gets a specific deployment.

    :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:
        name = message['params']['name']
        cluster_deploy = bus.storage.get(models.ClusterDeploy.new(name=name))
        cluster_deploy._validate()

        return create_jsonrpc_response(message['id'],
                                       cluster_deploy.to_dict_safe())
    except models.ValidationError as error:
        LOGGER.info('Invalid data retrieved. "%s"', error)
        LOGGER.debug('Data="%s"', message['params'])
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INVALID_REQUEST'])
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #2
0
def create_cluster_deploy(message, bus):
    """
    Creates a new cluster deployment.

    :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_deploy = models.ClusterDeploy.new(
            name=message['params'].get('name'),
            version=message['params'].get('version'))
        cluster_deploy._validate()

        result = bus.request(
            'jobs.clusterexec.deploy',
            params=[cluster_deploy.name, cluster_deploy.version])
        return create_jsonrpc_response(message['id'], result['result'])
    except models.ValidationError as error:
        LOGGER.info('Invalid data provided. "%s"', error)
        LOGGER.debug('Data="%s"', message['params'])
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INVALID_REQUEST'])
    except Exception as error:
        LOGGER.debug('Error creating ClusterDeploy: %s: %s', type(error),
                     error)
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #3
0
def get_cluster_operation(model_cls, message, bus):
    """
    Gets a specific operation based on the model_cls.

    :param model_cls: The model class to use.
    :type model_cls: class
    :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:
        name = message['params']['name']
        model = bus.storage.get(model_cls.new(name=name))
        model._validate()

        return create_jsonrpc_response(message['id'], model.to_dict_safe())
    except models.ValidationError as error:
        LOGGER.info('Invalid data retrieved. "%s"', error)
        LOGGER.debug('Data="%s"', message['params'])
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INVALID_REQUEST'])
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error getting %s: %s: %s', model_cls.__name__,
                     type(error), error)
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #4
0
def delete_container_manager(message, bus):
    """
    Deletes an exisiting ContainerManagerConfig.

    :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:
        name = message['params']['name']
        LOGGER.debug(
            'Attempting to delete ContainerManagerConfig "{}"'.format(name))
        bus.storage.delete(models.ContainerManagerConfig.new(name=name))
        return create_jsonrpc_response(message['id'], [])
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error deleting ContainerManagerConfig: {}: {}'.format(
            type(error), error))
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #5
0
def delete_cluster(message, bus):
    """
    Deletes an existing 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:
        name = message['params']['name']
        LOGGER.debug('Attempting to delete cluster "%s"', name)
        cluster = bus.storage.get_cluster(name)
        if cluster.container_manager:
            params = [cluster.container_manager]
            bus.request('container.remove_all_nodes', params=params)
        bus.storage.delete(cluster)
        return create_jsonrpc_response(message['id'], [])
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error deleting cluster: %s: %s'.format(
            type(error), error))
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #6
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
    """
    try:
        name = message['params']['name']
        cluster = bus.storage.get_cluster(name)
        LOGGER.debug('Cluster found: {}'.format(cluster.name))
        LOGGER.debug('Returning: {}'.format(cluster.hostset))
        return create_jsonrpc_response(
            message['id'], result=cluster.hostset)
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(
            message, error, JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error listing cluster: {}: {}'.format(
            type(error), error))
        return create_jsonrpc_error(
            message, error, JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #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:
        address = message['params']['address']
        host = bus.storage.get_host(address)
        container_manager = {}

        # Find the host's container manager status (if applicable)
        container = bus.storage.list(models.Clusters)
        for cluster in container.clusters:
            if address in cluster.hostset:
                if cluster.container_manager:
                    try:
                        params = [cluster.container_manager, address]
                        container_manager = bus.request(
                            'container.get_node_status', params=params)
                    except _bus.ContainerManagerError as error:
                        # If we fail to get the container manager's
                        # status for the host, leave that part of the
                        # status structure empty.
                        pass

                # A host can only be part of one cluster so break the loop.
                break

        status = models.HostStatus.new(
            host={
                'last_check': host.last_check,
                'status': host.status,
            },
            container_manager=container_manager,
            # TODO: Update when we add other types.
            type='host_only')

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

        return create_jsonrpc_response(message['id'], status.to_dict_safe())
    except _bus.RemoteProcedureCallError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Host Status exception caught for {0}: {1}:{2}'.format(
            address, type(error), error))
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #8
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:
        address = message['params']['host']
        name = message['params']['name']
    except KeyError as error:
        return create_jsonrpc_error(
            message, error, JSONRPC_ERRORS['BAD_REQUEST'])

    try:
        host = bus.storage.get_host(address)
        cluster = bus.storage.get_cluster(name)
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(
            message, error, JSONRPC_ERRORS['NOT_FOUND'])

    if host.address not in cluster.hostset:
        # FIXME: Need more input validation.
        #        - 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.

        if host_suitable_for_cluster(host):
            cluster.hostset.append(host.address)
            bus.storage.save(cluster)

            # Register new host with the cluster's container manager
            # (if applicable), and update its status.
            update_new_cluster_member_status(bus, cluster, host)
        else:
            msg = (
                'Host {} (status: {}) not ready to join cluster '
                '"{}"'.format(host.address, host.status, cluster.name))
            LOGGER.error(msg)
            return create_jsonrpc_error(
                message, msg, JSONRPC_ERRORS['METHOD_NOT_ALLOWED'])

    # Return back the host in a list
    return create_jsonrpc_response(message['id'], [host.address])
コード例 #9
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:
        host = message['params']['host']
        name = message['params']['name']
        cluster = bus.storage.get_cluster(name)
        if host in cluster.hostset:
            # Return back the host in a list
            return create_jsonrpc_response(message['id'], [host])
        else:
            return create_jsonrpc_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_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #10
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:
        name = message['params']['name']
        bus.storage.get_cluster(name)
        LOGGER.debug('Creation of already exisiting cluster %s requested.',
                     name)
    except Exception as error:
        LOGGER.debug('Brand new cluster being created.')

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

    try:
        cluster = bus.storage.save(models.Cluster.new(**message['params']))
        return create_jsonrpc_response(message['id'], cluster.to_dict_safe())
    except models.ValidationError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INVALID_REQUEST'])
コード例 #11
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:
        host = message['params']['host']
        name = message['params']['name']
        cluster = bus.storage.get_cluster(name)
        if host in cluster.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.hostset.index(host)
            cluster.hostset.pop(idx)
            bus.storage.save(cluster)

            # Remove from container manager (if applicable)
            if cluster.container_manager:
                params = [cluster.container_manager, host]
                bus.request('container.remove_node', params=params)

        return create_jsonrpc_response(message['id'], [])
    except Exception as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
コード例 #12
0
def create_cluster_operation(model_cls, message, bus, routing_key):
    """
    Creates a new operation based on the model_cls.

    :param model_cls: The model class to use.
    :type model_cls: class
    :param message: jsonrpc message structure.
    :type message: dict
    :param bus: Bus instance.
    :type bus: commissaire_http.bus.Bus
    :returns: A jsonrpc structure.
    :param routing_key: Routing key for the cluster operation request.
    :type routing_key: str
    :rtype: dict
    """

    # Verify cluster exists first
    cluster_name = message['params']['name']
    try:
        bus.storage.get_cluster(cluster_name)
        LOGGER.debug('Found cluster "%s"', cluster_name)
    except:
        error_msg = 'Cluster "{}" does not exist.'.format(cluster_name)
        LOGGER.debug(error_msg)
        return create_jsonrpc_error(message, error_msg,
                                    JSONRPC_ERRORS['NOT_FOUND'])

    try:
        model = model_cls.new(
            name=cluster_name,
            started_at=datetime.datetime.utcnow().isoformat())
        model._validate()

        # XXX Assumes the only method argument is cluster_name.
        result = bus.request(routing_key, params=[cluster_name])
        return create_jsonrpc_response(message['id'], result['result'])
    except models.ValidationError as error:
        LOGGER.info('Invalid data provided. "%s"', error)
        LOGGER.debug('Data="%s"', message['params'])
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INVALID_REQUEST'])
    except Exception as error:
        LOGGER.debug('Error creating %s: %s: %s', model_cls.__name__,
                     type(error), error)
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #13
0
 def test_create_jsonrpc_error(self):
     """
     Ensure create_jsonrpc_error returns a proper error structure.
     """
     result = handlers.create_jsonrpc_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'])
コード例 #14
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.storage.delete(models.Host.new(address=address))
        # TODO: kick off service job to remove the host?

        try:
            # Remove from a cluster
            container = bus.storage.list(models.Clusters)
            for cluster in container.clusters:
                if address in cluster.hostset:
                    LOGGER.info('Removing host "{}" from cluster "{}"'.format(
                        address, cluster.name))
                    cluster.hostset.pop(cluster.hostset.index(address))
                    bus.storage.save(cluster)

                    # Remove from container manager (if applicable)
                    if cluster.container_manager:
                        params = [cluster.container_manager, address]
                        bus.request('container.remove_node', params=params)

                    # A host can only be part of one cluster so break the loop
                    break
        except _bus.RemoteProcedureCallError as error:
            LOGGER.info('{} not part of a cluster.'.format(address))

        return create_jsonrpc_response(message['id'], [])
    except _bus.RemoteProcedureCallError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error deleting host: {}: {}'.format(type(error), error))
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #15
0
ファイル: networks.py プロジェクト: tbielawa/commissaire-http
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:
        name = message['params']['name']
        LOGGER.debug('create_network params: {}'.format(message['params']))
        # Check to see if we already have a network with that name
        input_network = models.Network.new(**message['params'])
        saved_network = bus.storage.get(input_network)
        LOGGER.debug(
            'Creation of already exisiting network "{0}" requested.'.format(
                name))

        # If they are the same thing then go ahead and return success
        if saved_network.to_dict() == input_network.to_dict():
            return create_jsonrpc_response(
                message['id'], saved_network.to_dict_safe())

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

    # Create the new network
    try:
        input_network = models.Network.new(**message['params'])
        saved_network = bus.storage.save(input_network)
        return create_jsonrpc_response(
            message['id'], saved_network.to_dict_safe())
    except models.ValidationError as error:
        return create_jsonrpc_error(
            message, error, JSONRPC_ERRORS['INVALID_REQUEST'])
コード例 #16
0
ファイル: networks.py プロジェクト: tbielawa/commissaire-http
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:
        name = message['params']['name']
        network = bus.storage.get_network(name)
        return create_jsonrpc_response(message['id'], network.to_dict_safe())
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(
            message, error, JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        return create_jsonrpc_error(
            message, error, JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #17
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:
        name = message['params']['name']
        LOGGER.debug('Attempting to delete network "%s"', name)
        bus.storage.delete(models.Network.new(name=name))
        return create_jsonrpc_response(message['id'], [])
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        LOGGER.debug('Error deleting network: %s: %s', type(error), error)
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #18
0
def get_container_manager(message, bus):
    """
    Gets a specific ContainerManagerConfig.

    :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:
        name = message['params']['name']
        container_manager_cfg = bus.storage.get(
            models.ContainerManagerConfig.new(name=name))

        return create_jsonrpc_response(message['id'],
                                       container_manager_cfg.to_dict_safe())
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
    except Exception as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #19
0
def list_networks(message, bus):
    """
    Lists all networks.

    :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:
        container = bus.storage.list(models.Networks)
        return create_jsonrpc_response(
            message['id'], [network.name for network in container.networks])
    except Exception as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INTERNAL_ERROR'])
コード例 #20
0
def get_host(message, bus):
    """
    Gets a specific 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']
        host = bus.storage.get_host(address)
        return create_jsonrpc_response(message['id'], host.to_dict_safe())
    except _bus.RemoteProcedureCallError as error:
        LOGGER.debug('Client requested a non-existant host: "{}"'.format(
            message['params']['address']))
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
コード例 #21
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:
        address = message['params']['address']
        host = bus.storage.get_host(address)
        creds = {
            'remote_user': host.remote_user,
            'ssh_priv_key': host.ssh_priv_key
        }
        return create_jsonrpc_response(message['id'], creds)
    except _bus.RemoteProcedureCallError as error:
        LOGGER.debug(
            'Client requested a non-existant host: "{}"'.format(address))
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])
コード例 #22
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="%s", new_hosts="%s"', old_hosts, new_hosts)
    except Exception as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['BAD_REQUEST'])

    try:
        name = message['params']['name']
        cluster = bus.storage.get_cluster(name)
    except _bus.StorageLookupError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['NOT_FOUND'])

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

    # FIXME: Need more input validation.  For each new host,
    #        - Does the host already belong to another cluster?

    # Only verify *new* hosts are suitable to add to the cluster.
    # Rejecting existing cluster members would be surprising to users.
    actual_new_hosts = new_hosts.difference(old_hosts)
    LOGGER.debug('Checking status of new hosts (ignoring existing): %s',
                 ', '.join(actual_new_hosts))
    list_of_hosts = bus.storage.get_many(
        [models.Host.new(address=x) for x in actual_new_hosts])
    hosts_not_ready = [
        host.address for host in list_of_hosts
        if not host_suitable_for_cluster(host)
    ]
    if hosts_not_ready:
        msg = 'Hosts not ready to join cluster "{}": {}'.format(
            name, ','.join(hosts_not_ready))
        LOGGER.error(msg)
        return create_jsonrpc_error(message, msg,
                                    JSONRPC_ERRORS['METHOD_NOT_ALLOWED'])

    # 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.hostset = list(new_hosts)
    saved_cluster = bus.storage.save(cluster)

    # Register newly added hosts with the cluster's container manager
    # (if applicable), and update their status.
    update_new_cluster_member_status(bus, cluster, *list_of_hosts)

    # XXX Using to_dict() instead of to_dict_safe() to include hostset.
    return create_jsonrpc_response(message['id'], saved_cluster.to_dict())
コード例 #23
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 create_jsonrpc_error(
            message, '"address" must be given in the url or in the PUT body',
            JSONRPC_ERRORS['BAD_REQUEST'])

    # If a cluster if provided, grab it from storage
    cluster_data = {}
    cluster_name = message['params'].get('cluster')
    if cluster_name:
        cluster = _does_cluster_exist(bus, cluster_name)
        if not cluster:
            return create_jsonrpc_error(message, 'Cluster does not exist',
                                        JSONRPC_ERRORS['CONFLICT'])
        else:
            cluster_data = cluster.to_dict()
            LOGGER.debug('Found cluster. Data: "{}"'.format(cluster))
    try:
        host = bus.storage.get_host(address)
        LOGGER.debug('Host "{}" already exisits.'.format(address))

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

        # Verify the host is in the cluster if it is expected
        if cluster_name and address not in cluster.hostset:
            LOGGER.debug('Host "{}" is not in cluster "{}"'.format(
                address, cluster_name))
            return create_jsonrpc_error(message, 'Host not in cluster',
                                        JSONRPC_ERRORS['CONFLICT'])

        # Return out now. No more processing needed.
        return create_jsonrpc_response(message['id'], host.to_dict_safe())

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

    # Save the host to the cluster if it isn't already there
    if cluster_name:
        if address not in cluster.hostset:
            cluster.hostset.append(address)
            bus.storage.save(cluster)
            LOGGER.debug('Saved host "{}" to cluster "{}"'.format(
                address, cluster_name))

    try:
        host = bus.storage.save(models.Host.new(**message['params']))

        # pass this off to the investigator
        bus.notify('jobs.investigate',
                   params={
                       'address': address,
                       'cluster_data': cluster_data
                   })

        # Push the host to the Watcher queue
        watcher_record = models.WatcherRecord(
            address=address, last_check=_dt.utcnow().isoformat())
        bus.producer.publish(watcher_record.to_json(), 'jobs.watcher')

        return create_jsonrpc_response(message['id'], host.to_dict_safe())
    except models.ValidationError as error:
        return create_jsonrpc_error(message, error,
                                    JSONRPC_ERRORS['INVALID_REQUEST'])