Exemple #1
0
    def _add_or_update_dns_records(self, task_id, ip_address):
        hostname = self.node.hostname
        admin_net = ip_address.subnet
        record_cls = RecordView.Record

        if admin_net.dns_domain:
            logger.info('Adding or updating forward A DNS record for node %s',
                        hostname)
            RecordView.add_or_update_record(self.request,
                                            record_cls.A,
                                            admin_net.dns_domain,
                                            hostname,
                                            task_id=task_id,
                                            related_obj=self.node)

        if admin_net.ptr_domain:
            logger.info(
                'Adding or updating reverse PTR DNS record for node %s',
                hostname)
            RecordView.add_or_update_record(self.request,
                                            record_cls.PTR,
                                            admin_net.ptr_domain,
                                            record_cls.get_reverse(
                                                ip_address.ip),
                                            task_id=task_id,
                                            related_obj=self.node)
Exemple #2
0
    def _delete_dns_records(request, task_id, node, hostname, ip_address):
        if ip_address:
            admin_net = ip_address.subnet
            record_cls = RecordView.Record

            if admin_net.dns_domain:
                logger.info('Deleting forward A DNS record for node %s', hostname)
                RecordView.delete_record(request, record_cls.A, admin_net.dns_domain, hostname,
                                         task_id=task_id, related_obj=node)

            if admin_net.ptr_domain:
                logger.info('Deleting reverse PTR DNS record for node %s', hostname)
                RecordView.delete_record(request, record_cls.PTR, admin_net.ptr_domain,
                                         record_cls.get_reverse(ip_address.ip), task_id=task_id, related_obj=node)
Exemple #3
0
def ptr_form(request, hostname, nic_id):
    """
    Ajax page for PTR form validation.
    """
    vm = get_vm(request, hostname)

    try:
        nic_ip = vm.json_get_nics()[int(nic_id) - 1]['ip']
        ptr = RecordView.Record.get_record_PTR(nic_ip)
        if not ptr:
            raise Exception('PTR Record not found')
    except Exception:
        raise Http404

    ptrform = PTRForm(request.POST, prefix='ptr')

    if ptrform.is_valid():
        if ptrform.cleaned_data['content'] == ptr.content:
            return HttpResponse(None, status=204)
        else:
            res = RecordView.internal_response(request,
                                               'PUT',
                                               ptr,
                                               ptrform.cleaned_data,
                                               related_obj=vm)

            if res.status_code in (200, 201):
                return HttpResponse(None, status=201)
            else:
                ptrform.set_api_errors(res.data)

    return render(request, 'gui/vm/ptr_form.html', {'ptrform': ptrform})
Exemple #4
0
def _save_node_ip_address(task_id, node):
    """Helper function for saving IP address and creating DNS records of a new compute node"""
    assert node.address

    try:
        ip_address = node.create_ip_address()
    except IPAddress.DoesNotExist as exc:
        logger.warning(
            'Could not save node %s IP address "%s" into admin network (%s)',
            node, node.address, exc)
        return

    logger.info('Saving node %s IP address "%s" into admin network', node,
                node.ip_address)
    ip_address.save()

    admin_net = node.ip_address.subnet  # The network was updated by init_mgmt()
    # Reload Subnet object because it is cached inside node instance
    admin_net = admin_net.__class__.objects.get(pk=admin_net.pk)
    # We need a request object
    request = get_dummy_request(DefaultDc(), 'POST', system_user=True)
    record_cls = RecordView.Record

    if admin_net.dns_domain and admin_net.dns_domain == node.domain_name:
        logger.info('Creating forward A DNS record for node %s', node)
        # This will fail silently
        RecordView.add_or_update_record(request,
                                        record_cls.A,
                                        admin_net.dns_domain,
                                        node.hostname,
                                        node.address,
                                        task_id=task_id,
                                        related_obj=node)

    if admin_net.ptr_domain:
        logger.info('Creating reverse PTR DNS record for node %s', node)
        # This will fail silently
        RecordView.add_or_update_record(request,
                                        record_cls.PTR,
                                        admin_net.ptr_domain,
                                        record_cls.get_reverse(node.address),
                                        node.hostname,
                                        task_id=task_id,
                                        related_obj=node)
Exemple #5
0
def dns_record_list(request, name, data=None):
    """
    List (:http:get:`GET </dns/domain/(name)/record>`) all DNS records which belong to a DNS domain.
    Delete (:http:delete:`DELETE </dns/domain/(name)/record>`) specified DNS records that belong to a DNS domain.

    .. http:get:: /dns/domain/(name)/record

        :DC-bound?:
            * |dc-yes| - ``domain.dc_bound=true``
            * |dc-no| - ``domain.dc_bound=false``
        :Permissions:
            * |DnsAdmin| or |DomainOwner|
        :Asynchronous?:
            * |async-no|
        :arg name: **required** - Domain name
        :type name: string
        :arg data.full: Return list of objects with all record details (default: false)
        :type data.full: boolean
        :arg data.order_by: :ref:`Available fields for sorting <order_by>`: ``id``, ``name``, ``type``, ``ttl``, \
``disabled``, ``changed`` (default: ``id``)
        :type data.order_by: string
        :status 200: SUCCESS
        :status 403: Forbidden

    .. http:delete:: /dns/domain/(name)/record

        :DC-bound?:
            * |dc-yes| - ``domain.dc_bound=true``
            * |dc-no| - ``domain.dc_bound=false``
        :Permissions:
            * |DnsAdmin| or |DomainOwner|
        :Asynchronous?:
            * |async-no|
        :arg name: **required** - Domain name
        :type name: string
        :arg data.records: **required** List of DNS record ids to be deleted
        :type data.records: array
        :status 200: SUCCESS
        :status 400: FAILURE
        :status 403: Forbidden
        :status 404: Domain not found / Record not found
        :status 412: Invalid records
    """
    if request.method == 'POST':
        return dns_record(request, name, 0, data=data)
    return RecordView(request, name, None, data).response(many=True)
Exemple #6
0
def dns_record_list(request, name, data=None):
    """
    List (:http:get:`GET </dns/domain/(name)/record>`) all DNS records which belong to a DNS domain.

    .. http:get:: /dns/domain/(name)/record

        :DC-bound?:
            * |dc-yes| - ``domain.dc_bound=true``
            * |dc-no| - ``domain.dc_bound=false``
        :Permissions:
            * |DnsAdmin| or |DomainOwner|
        :Asynchronous?:
            * |async-no|
        :arg data.full: Return list of objects with all record details (default: false)
        :type data.full: boolean
        :arg data.order_by: :ref:`Available fields for sorting <order_by>`: ``id``, ``name``, ``type``, ``ttl``, \
``disabled``, ``changed`` (default: ``id``)
        :type data.order_by: string
        :status 200: SUCCESS
        :status 403: Forbidden
    """
    if request.method == 'POST':
        return dns_record(request, name, 0, data=data)
    return RecordView(request, name, None, data).response(many=True)
Exemple #7
0
def node_sysinfo_cb(result, task_id, node_uuid=None):
    """
    A callback function for updating Node.json (sysinfo).

    node_uuid will be set only if called via API or GUI
    """
    # in case the callback is called by restarting erigonesd:fast service on compute node, the meta dict lacks
    # a lot of information; msg is required as part of exception logging inside callback decorator
    # therefore we set it explicitly
    result['meta']['msg'] = LOG_NODE_UPDATE

    if result['returncode'] != 0:
        logger.error(
            'Found nonzero return code in result from esysinfo command on %s',
            node_uuid)
        raise TaskException(result,
                            'Got bad return code (%s)' % result['returncode'])

    stdout = result.pop('stdout', '')
    result.pop('stderr', None)
    node_new = False

    try:
        esysinfo = parse_esysinfo(stdout)
        img_sources = esysinfo.pop('img_sources')
        img_initial = esysinfo.pop('img_initial')
    except Exception as e:
        logger.error(
            'Could not parse output from esysinfo command on %s. Error: %s',
            node_uuid, e)
        logger.exception(e)
        raise TaskException(result, 'Could not parse esysinfo output')
    else:
        uuid = esysinfo['sysinfo']['UUID']

    try:
        node = Node.objects.get(uuid=uuid)
    except Node.DoesNotExist:
        # The head node must be in online state during the admin DC initialization and each compute node must be in
        # online state during ssh key exchange.
        node_new = True
        is_head = not Node.objects.exists()
        logger.warn('Creating NEW node from sysinfo output from %s', node_uuid)
        node = Node.create_from_sysinfo(uuid,
                                        esysinfo,
                                        status=Node.ONLINE,
                                        is_head=is_head)
        node_created.send(task_id, node=node)  # Signal!
        result[
            'message'] = 'Successfully created new compute node %s' % node.hostname
        task_log_success(task_id,
                         msg=LOG_NODE_CREATE,
                         obj=node,
                         task_result=result,
                         update_user_tasks=True)
        sshkey_changed = bool(node.sshkey)

        if node.is_head:
            logger.warn(
                'New node %s is the first node ever created - assuming head node status. '
                'Initializing mgmt system and creating admin DC', node)
            from api.system.init import init_mgmt
            try:
                init_mgmt(node, images=img_initial)
            except Exception as e:
                logger.exception(e)
                result[
                    'message'] = 'Error while initializing admin datacenter (%s)' % e
                task_log_error(task_id,
                               msg=LOG_NODE_CREATE,
                               obj=node,
                               task_result=result,
                               update_user_tasks=True)

        logger.info('Saving node %s IP address "%s" into admin network', node,
                    node.ip_address)
        try:  # We should proceed even if the IP address is not registered
            node.ip_address.save()
        except Exception as e:
            logger.exception(e)
        else:
            admin_net = node.ip_address.subnet  # The network was updated by init_mgmt()
            # Reload Subnet object because it is cached inside node instance
            admin_net = admin_net.__class__.objects.get(pk=admin_net.pk)
            # We need a request object
            request = get_dummy_request(DefaultDc(), 'POST', system_user=True)
            record_cls = RecordView.Record

            if admin_net.dns_domain and admin_net.dns_domain == node.domain_name:
                logger.info('Creating forward A DNS record for node %s', node)
                # This will fail silently
                RecordView.add_or_update_record(request,
                                                record_cls.A,
                                                admin_net.dns_domain,
                                                node.hostname,
                                                node.address,
                                                task_id=task_id,
                                                related_obj=node)

            if admin_net.ptr_domain:
                logger.info('Creating reverse PTR DNS record for node %s',
                            node)
                # This will fail silently
                RecordView.add_or_update_record(request,
                                                record_cls.PTR,
                                                admin_net.ptr_domain,
                                                record_cls.get_reverse(
                                                    node.address),
                                                node.hostname,
                                                task_id=task_id,
                                                related_obj=node)

    else:
        sshkey_changed = node.sshkey_changed(esysinfo)

        if node.sysinfo_changed(esysinfo) or sshkey_changed:
            logger.warn('Updating node %s json with sysinfo output from %s',
                        node, node_uuid)
            node.update_from_sysinfo(esysinfo)  # Will save public SSH key too
            node_json_changed.send(task_id, node=node)  # Signal!
            result[
                'message'] = 'Successfully updated compute node %s' % node.hostname
            task_log_success(task_id,
                             msg=LOG_NODE_UPDATE,
                             obj=node,
                             task_result=result,
                             update_user_tasks=True)
        else:
            result[
                'message'] = 'No changes detected on compute node %s' % node.hostname
            task_log_success(task_id,
                             msg=LOG_NODE_UPDATE,
                             obj=node,
                             task_result=result,
                             update_user_tasks=True)

    if sshkey_changed:
        logger.warn(
            'SSH key has changed on node %s - creating authorized_keys synchronization tasks',
            node)
        try:
            run_node_authorized_keys_sync()
        except Exception as e:
            logger.exception(e)

    try:
        run_node_img_sources_sync(node, node_img_sources=img_sources)
    except Exception as e:
        logger.exception(e)

    if node_new:
        node.del_initializing()
        # Used by esdc-ee to change node status to unlicensed
        node_status = getattr(settings, 'VMS_NODE_STATUS_DEFAULT', None)

        if node_status:
            node.save_status(
                node_status)  # Set node status (most probably to unlicensed)
    else:
        # Always run vm_status_all for an old compute node
        vm_status_all(task_id, node)

        # Sync snapshots and backup for every node storage
        try:
            NodeVmSnapshotList.sync(node)
        except Exception as e:
            logger.exception(e)

    return result
Exemple #8
0
def dns_record(request, name, record_id, data=None):
    """
    Show (:http:get:`GET </dns/domain/(name)/record/(record_id)>`),
    create (:http:post:`POST </dns/domain/(name)/record>`,
    update (:http:put:`PUT </dns/domain/(name)/record/(record_id)>`) or
    delete (:http:delete:`DELETE </dns/domain/(name)/record/(record_id)>`)
    a DNS record.

    .. http:get:: /dns/domain/(name)/record/(record_id)

        :DC-bound?:
            * |dc-yes| - ``domain.dc_bound=true``
            * |dc-no| - ``domain.dc_bound=false``
        :Permissions:
            * |DnsAdmin| or |DomainOwner|
        :Asynchronous?:
            * |async-no|
        :arg name: **required** - Domain name
        :type name: string
        :arg record_id: **required** - DNS record ID
        :type record_id: integer
        :status 200: SUCCESS
        :status 403: Forbidden
        :status 404: Domain not found / Record not found

    .. http:post:: /dns/domain/(name)/record

        :DC-bound?:
            * |dc-yes| - ``domain.dc_bound=true``
            * |dc-no| - ``domain.dc_bound=false``
        :Permissions:
            * |DnsAdmin| or |DomainOwner|
        :Asynchronous?:
            * |async-no|
        :arg name: **required** - Domain name
        :type name: string
        :arg data.name: **required** - The name of the DNS record - the full URI the DNS server should pick up on
        :type data.name: string
        :arg data.type: **required** - DNS record type (one of: A, AAAA, CERT, CNAME, HINFO, KEY, LOC, MX, NAPTR, \
NS, PTR, RP, SOA, SPF, SSHFP, SRV, TLSA, TXT)
        :type data.type: string
        :arg data.content: **required** - DNS record content - the answer of the DNS query
        :type data.content: string
        :arg data.ttl: How long (seconds) the DNS client is allowed to remember this record (default: 3600)
        :type data.ttl: integer
        :arg data.prio: Priority used by some record types (default: 0)
        :type data.prio: integer
        :arg data.disabled: If set to true, this record is hidden from DNS clients (default: false)
        :type data.disabled: boolean
        :status 201: SUCCESS
        :status 400: FAILURE
        :status 403: Forbidden
        :status 404: Domain not found
        :status 406: Record already exists

    .. http:put:: /dns/domain/(name)/record/(record_id)

        :DC-bound?:
            * |dc-yes| - ``domain.dc_bound=true``
            * |dc-no| - ``domain.dc_bound=false``
        :Permissions:
            * |DnsAdmin| or |DomainOwner|
        :Asynchronous?:
            * |async-no|
        :arg name: **required** - Domain name
        :type name: string
        :arg record_id: **required** - DNS record ID
        :type record_id: integer
        :arg data.name: The name of the DNS record - the full URI the DNS server should pick up on
        :type data.name: string
        :arg data.type: DNS record type (one of: A, AAAA, CERT, CNAME, HINFO, KEY, LOC, MX, NAPTR, NS, PTR, RP, \
SOA, SPF, SSHFP, SRV, TLSA, TXT)
        :type data.type: string
        :arg data.content: DNS record content - the answer of the DNS query
        :type data.content: string
        :arg data.ttl: How long (seconds) the DNS client is allowed to remember this record
        :type data.ttl: integer
        :arg data.prio: Priority used by some record types
        :type data.prio: integer
        :arg data.disabled: If set to true, this record is hidden from DNS clients
        :type data.disabled: boolean
        :status 200: SUCCESS
        :status 400: FAILURE
        :status 403: Forbidden
        :status 404: Domain not found / Record not found

    .. http:delete:: /dns/domain/(name)/record/(record_id)

        :DC-bound?:
            * |dc-yes| - ``domain.dc_bound=true``
            * |dc-no| - ``domain.dc_bound=false``
        :Permissions:
            * |DnsAdmin| or |DomainOwner|
        :Asynchronous?:
            * |async-no|
        :arg name: **required** - Domain name
        :type name: string
        :arg record_id: **required** - DNS record ID
        :type record_id: integer
        :status 200: SUCCESS
        :status 400: FAILURE
        :status 403: Forbidden
        :status 404: Domain not found / Record not found

    """
    return RecordView(request, name, record_id, data).response()