Пример #1
0
    def stop(self, taskid, stop_type, msg):
        """
        Cancels the given job. Note that when cancelling some part of a job 
        (for example, by passing *taskid* starting with ``R:`` to indicate 
        a particular recipe within a job) the entire job is cancelled.

        :param taskid: see above
        :type taskid: string
        :param stop_type: must be ``'cancel'`` (other values are reserved for 
            Beaker's internal use)
        :type stop_type: string
        :param msg: reason for cancelling
        :type msg: string
        """
        task_type, task_id = taskid.split(":")
        if task_type.upper() in self.stoppable_task_types.keys():
            try:
                task = self.stoppable_task_types[task_type.upper()].by_id(int(task_id))
            except (InvalidRequestError, ValueError):
                raise BX(_("Invalid %s %s" % (task_type, task_id)))
        else:
            raise BX(_("Task type %s is not stoppable" % (task_type)))
        if stop_type not in task.stop_types:
            raise BX(_('Invalid stop_type: %s, must be one of %s' %
                             (stop_type, task.stop_types)))
        if not task.can_stop(identity.current.user):
            raise BX(_("You don't have permission to %s %s" % (stop_type,
                                                               taskid)))
        kwargs = dict(msg = msg)
        task.record_activity(user=identity.current.user, service=u'XMLRPC',
                             field=u'Status', action=u'Cancelled', old='', new='')
        try:
            return getattr(task, stop_type)(**kwargs)
        except StaleTaskStatusException:
            raise BX(_(u"Could not cancel job id %s. Please try later" % task_id))
Пример #2
0
 def set(self, value, valid_from=None, user=None):
     if user is None:
         try:
             user = identity.current.user
         except AttributeError:
             raise BX(_('Settings may not be changed anonymously'))
     if valid_from:
         if valid_from < datetime.utcnow():
             raise BX(_('%s is in the past') % valid_from)
     self.value_class(self, value, user, valid_from)
Пример #3
0
    def create(self, kw):
        """
        Creates a new group.

        The *kw* argument must be an XML-RPC structure (dict)
        specifying the following keys:

            'group_name'
                 Group name (maximum 16 characters)
            'display_name'
                 Group display name
            'description'
                 Group description
            'ldap'
                 Populate users from LDAP (True/False)

        Returns a message whether the group was successfully created or
        raises an exception on failure.

        """
        display_name = kw.get('display_name')
        group_name = kw.get('group_name')
        description = kw.get('description')
        ldap = kw.get('ldap')
        password = kw.get('root_password')

        if ldap and not identity.current.user.is_admin():
            raise BX(_(u'Only admins can create LDAP groups'))
        if ldap and not config.get("identity.ldap.enabled", False):
            raise BX(_(u'LDAP is not enabled'))
        try:
            group = Group.by_name(group_name)
        except NoResultFound:
            group = Group()
            session.add(group)
            group.record_activity(user=identity.current.user,
                                  service=u'XMLRPC',
                                  field=u'Group',
                                  action=u'Created')
            group.display_name = display_name
            group.group_name = group_name
            group.description = description
            group.root_password = password
            if ldap:
                group.membership_type = GroupMembershipType.ldap
                group.refresh_ldap_members()
            else:
                group.add_member(identity.current.user,
                                 is_owner=True,
                                 service=u'XMLRPC',
                                 agent=identity.current.user)
            return 'Group created: %s.' % group_name
        else:
            raise BX(_(u'Group already exists: %s.' % group_name))
Пример #4
0
    def members(self, group_name):
        """
        List the members of an existing group.

        :param group_name: An existing group name
        :type group_name: string

        Returns a list of the members (a dictionary containing each
        member's username, email, and whether the member is an owner
        or not).

        """
        try:
            group = Group.by_name(group_name)
        except NoResultFound:
            raise BX(_(u'Group does not exist: %s.' % group_name))

        users = []
        for u in group.users:
            user = {}
            user['username'] = u.user_name
            user['email'] = u.email_address
            if group.has_owner(u):
                user['owner'] = True
            else:
                user['owner'] = False
            users.append(user)

        return users
Пример #5
0
    def to_xml(self, taskid, clone=False, exclude_enclosing_job=True, include_logs=True):
        """
        Returns an XML representation of the given job component, including its 
        current state.

        :param taskid: see above
        :type taskid: string
        :param clone: If True, returns XML suitable for submitting back to 
            Beaker. Otherwise, the XML includes results.
        :type clone: bool
        :param exclude_enclosing_job: If False, returns <job> as the root 
            element even when requesting a recipe set or recipe. This is useful 
            when cloning, in order to always produce a complete job definition.
        :type exclude_enclosing_job: bool
        :param include_logs: If True (the default), the results XML includes 
            links to all logs. This can make the results XML substantially larger.
        :type include_logs: bool
        """
        task_type, task_id = taskid.split(":")
        if task_type.upper() in self.task_types.keys():
            try:
                task = self.task_types[task_type.upper()].by_id(task_id)
            except InvalidRequestError:
                raise BX(_("Invalid %s %s" % (task_type, task_id)))
        return lxml.etree.tostring(
                task.to_xml(clone=clone,
                            include_enclosing_job=not exclude_enclosing_job,
                            include_logs=include_logs),
                xml_declaration=False, encoding='UTF-8')
Пример #6
0
 def set_name(self, user, service, group_name):
     """
     Set a group's name and record any change as group activity
     """
     old_group_name = self.group_name
     if group_name != old_group_name:
         if self.is_protected_group():
             raise BX(_(u'Cannot rename protected group %r as %r'
                                           % (old_group_name, group_name)))
         self.group_name = group_name
         self.record_activity(user=user, service=service,
                              field=u'Name',
                              old=old_group_name, new=group_name)
Пример #7
0
    def set_name(self, user, service, group_name):
        """Set a group's name and record any change as group activity

        Passing None or the empty string means "leave this value unchanged"
        """
        old_group_name = self.group_name
        if group_name and group_name != old_group_name:
            if self.is_protected_group():
                raise BX(_(u'Cannot rename protected group %r as %r'
                                              % (old_group_name, group_name)))
            self.group_name = group_name
            self.record_activity(user=user, service=service,
                                 field=u'Name',
                                 old=old_group_name, new=group_name)
Пример #8
0
    def to_xml(self, taskid, clone=False, from_job=True):
        """
        Returns an XML representation of the given job component, including its 
        current state.

        :param taskid: see above
        :type taskid: string
        """
        task_type, task_id = taskid.split(":")
        if task_type.upper() in self.task_types.keys():
            try:
                task = self.task_types[task_type.upper()].by_id(task_id)
            except InvalidRequestError:
                raise BX(_("Invalid %s %s" % (task_type, task_id)))
        return task.to_xml(clone, from_job).toxml()
Пример #9
0
    def power(self, action, fqdn, clear_netboot=False, force=False, delay=0):
        """
        Controls power for the system with the given fully-qualified domain 
        name.

        If the *clear_netboot* argument is True, the Cobbler netboot 
        configuration for the system will be cleared before power controlling.

        Controlling power for a system is not normally permitted when the 
        system is in use by someone else, because it is likely to interfere 
        with their usage. Callers may pass True for the *force* argument to 
        override this safety check.

        This method does not wait for Cobbler to report whether the power 
        control was succesful.

        :param action: 'on', 'off', or 'reboot'
        :type action: string
        :param fqdn: fully-qualified domain name of the system to be power controlled
        :type fqdn: string
        :param clear_netboot: whether to clear netboot configuration before powering
        :type clear_netboot: boolean
        :param force: whether to power the system even if it is in use
        :type force: boolean
        :param delay: number of seconds to delay before performing the action (default none)
        :type delay: int or float

        .. versionadded:: 0.6
        .. versionchanged:: 0.6.14
           No longer waits for completion of Cobbler power task.
        """
        system = System.by_fqdn(fqdn, identity.current.user)
        if not system.can_power(identity.current.user):
            raise InsufficientSystemPermissions(
                _(u'User %s does not have permission to power system %s') %
                (identity.current.user, system))
        if not force and system.user is not None \
                and system.user != identity.current.user:
            raise BX(_(u'System is in use'))
        if clear_netboot:
            system.clear_netboot(service=u'XMLRPC')
        system.action_power(action, service=u'XMLRPC', delay=delay)
        return system.fqdn  # because turbogears makes us return something
Пример #10
0
    def create_from_taskinfo(cls, raw_taskinfo):
        """Create a new task object based on details retrieved from an RPM"""

        tinfo = testinfo.parse_string(raw_taskinfo['desc'].decode('utf8'))

        if len(tinfo.test_name) > 255:
            raise BX(_("Task name should be <= 255 characters"))
        if tinfo.test_name.endswith('/'):
            raise BX(_(u'Task name must not end with slash'))
        if '//' in tinfo.test_name:
            raise BX(_(u'Task name must not contain redundant slashes'))

        task = cls.lazy_create(name=tinfo.test_name)

        # RPM is the same version we have. don't process
        if task.version == raw_taskinfo['hdr']['ver']:
            raise BX(
                _("Failed to import,  %s is the same version we already have" %
                  task.version))

        # if the task is already present, check if a downgrade has been requested
        if task.version:
            downgrade = cls.check_downgrade(task.version,
                                            raw_taskinfo['hdr']['ver'])
        else:
            downgrade = False

        task.version = raw_taskinfo['hdr']['ver']
        task.description = tinfo.test_description
        task.types = []
        task.bugzillas = []
        task.required = []
        task.runfor = []
        task.needs = []
        task.excluded_osmajor = []
        task.excluded_arch = []
        includeFamily = []
        for family in tinfo.releases:
            if family.startswith('-'):
                try:
                    if family.lstrip('-') not in task.excluded_osmajor:
                        task.excluded_osmajor.append(
                            TaskExcludeOSMajor(osmajor=OSMajor.by_name_alias(
                                family.lstrip('-'))))
                except InvalidRequestError:
                    pass
            else:
                try:
                    includeFamily.append(OSMajor.by_name_alias(family).osmajor)
                except InvalidRequestError:
                    pass
        families = set(['%s' % family.osmajor for family in OSMajor.query])
        if includeFamily:
            for family in families.difference(set(includeFamily)):
                if family not in task.excluded_osmajor:
                    task.excluded_osmajor.append(
                        TaskExcludeOSMajor(
                            osmajor=OSMajor.by_name_alias(family)))
        if tinfo.test_archs:
            arches = set(['%s' % arch.arch for arch in Arch.query])
            for arch in arches.difference(set(tinfo.test_archs)):
                if arch not in task.excluded_arch:
                    task.excluded_arch.append(
                        TaskExcludeArch(arch=Arch.by_name(arch)))
        task.avg_time = tinfo.avg_test_time
        for type in tinfo.types:
            ttype = TaskType.lazy_create(type=type)
            task.types.append(ttype)
        for bug in tinfo.bugs:
            task.bugzillas.append(TaskBugzilla(bugzilla_id=bug))
        task.path = tinfo.test_path
        # Bug 772882. Remove duplicate required package here
        # Avoid ORM insert in task_packages_required_map twice.
        tinfo.runfor = list(set(tinfo.runfor))
        for runfor in tinfo.runfor:
            package = TaskPackage.lazy_create(package=runfor)
            task.runfor.append(package)
        task.priority = tinfo.priority
        task.destructive = tinfo.destructive
        # Bug 772882. Remove duplicate required package here
        # Avoid ORM insert in task_packages_required_map twice.
        tinfo.requires = list(set(tinfo.requires))
        for require in tinfo.requires:
            package = TaskPackage.lazy_create(package=require)
            task.required.append(package)
        for need in tinfo.needs:
            task.needs.append(TaskPropertyNeeded(property=need))
        task.license = tinfo.license
        task.owner = tinfo.owner

        try:
            task.uploader = identity.current.user
        except identity.RequestRequiredException:
            task.uploader = User.query.get(1)

        task.valid = True

        return task, downgrade
Пример #11
0
    def create_from_taskinfo(cls, raw_taskinfo):
        """Create a new task object based on details retrieved from an RPM"""

        tinfo = testinfo.parse_string(raw_taskinfo['desc'].decode('utf8'))

        if len(tinfo.test_name) > 255:
            raise BX(_("Task name should be <= 255 characters"))
        if tinfo.test_name.endswith('/'):
            raise BX(_(u'Task name must not end with slash'))
        if '//' in tinfo.test_name: # pylint:disable=unsupported-membership-test
            raise BX(_(u'Task name must not contain redundant slashes'))

        existing_task = Task.query.filter(Task.name == tinfo.test_name).first()
        if existing_task is not None:
            task = existing_task
            # RPM is the same version we have. don't process
            if existing_task.version == raw_taskinfo['hdr']['ver']:
                raise BX(_("Failed to import,  %s is the same version we already have" % task.version))
            # if the task is already present, check if a downgrade has been requested
            downgrade = cls.check_downgrade(task.version, raw_taskinfo['hdr']['ver'])
        else:
            task = Task(name=tinfo.test_name)
            downgrade = False

        task.version = raw_taskinfo['hdr']['ver']
        task.description = tinfo.test_description
        task.types = []
        task.bugzillas = []
        task.required = []
        task.runfor = []
        task.needs = []
        task.excluded_osmajors = []
        task.exclusive_osmajors = []
        task.excluded_arches = []
        task.exclusive_arches = []
        for family in tinfo.releases:
            if family.startswith('-'):
                try:
                    osmajor = OSMajor.by_name_alias(family.lstrip('-'))
                    if osmajor not in task.excluded_osmajors:
                        task.excluded_osmajors.append(osmajor)
                except NoResultFound:
                    pass
            else:
                try:
                    osmajor = OSMajor.by_name_alias(family)
                    if osmajor not in task.exclusive_osmajors:
                        task.exclusive_osmajors.append(osmajor)
                except NoResultFound:
                    pass
        for value in tinfo.test_archs:
            if value.startswith('-'):
                try:
                    arch = Arch.by_name(value.lstrip('-'))
                except ValueError:
                    pass
                else:
                    if arch not in task.excluded_arches:
                        task.excluded_arches.append(arch)
            else:
                try:
                    arch = Arch.by_name(value)
                except ValueError:
                    pass
                else:
                    if arch not in task.exclusive_arches:
                        task.exclusive_arches.append(arch)
        task.avg_time = tinfo.avg_test_time
        for type in tinfo.types:
            ttype = TaskType.lazy_create(type=type)
            task.types.append(ttype)
        for bug in tinfo.bugs:
            task.bugzillas.append(TaskBugzilla(bugzilla_id=bug))
        task.path = tinfo.test_path
        # Bug 772882. Remove duplicate required package here
        # Avoid ORM insert in task_packages_required_map twice.
        tinfo.runfor = list(set(tinfo.runfor))
        for runfor in tinfo.runfor:
            package = TaskPackage.lazy_create(package=runfor)
            task.runfor.append(package)
        task.priority = tinfo.priority
        task.destructive = tinfo.destructive
        # Bug 772882. Remove duplicate required package here
        # Avoid ORM insert in task_packages_required_map twice.
        tinfo.requires = list(set(tinfo.requires))
        for require in tinfo.requires:
            package = TaskPackage.lazy_create(package=require)
            task.required.append(package)
        for need in tinfo.needs:
            task.needs.append(TaskPropertyNeeded(property=need))
        task.license = tinfo.license
        task.owner = tinfo.owner

        try:
            task.uploader = identity.current.user
        except identity.RequestRequiredException:
            task.uploader = User.query.get(1)

        task.valid = True

        return task, downgrade
Пример #12
0
    def modify(self, group_name, kw):
        """
        Modifies an existing group. You must be an owner of a group to modify any details.

        :param group_name: An existing group name
        :type group_name: string

        The *kw* argument must be an XML-RPC structure (dict)
        specifying the following keys:

            'group_name'
                 New group name (maximum 16 characters)
            'display_name'
                 New group display name
            'add_member'
                 Add user (username) to the group
            'remove_member'
                 Remove an existing user (username) from the group
            'root_password'
                 Change the root password of this group.

        Returns a message whether the group was successfully modified or
        raises an exception on failure.

        """
        # if not called from the bkr group-modify
        if not kw:
            raise BX(_('Please specify an attribute to modify.'))

        try:
            group = Group.by_name(group_name)
        except NoResultFound:
            raise BX(_(u'Group does not exist: %s.' % group_name))

        if group.membership_type == GroupMembershipType.ldap:
            if not identity.current.user.is_admin():
                raise BX(_(u'Only admins can modify LDAP groups'))
            if kw.get('add_member', None) or kw.get('remove_member', None):
                raise BX(_(u'Cannot edit membership of an LDAP group'))

        user = identity.current.user
        if not group.can_edit(user):
            raise BX(_('You are not an owner of group %s' % group_name))

        group_name = kw.get('group_name', None)
        if group_name:
            try:
                Group.by_name(group_name)
            except NoResultFound:
                pass
            else:
                if group_name != group.group_name:
                    raise BX(
                        _(u'Failed to update group %s: Group name already exists: %s'
                          % (group.group_name, group_name)))

            group.set_name(user, u'XMLRPC', kw.get('group_name', None))

        display_name = kw.get('display_name', None)
        if display_name:
            group.set_display_name(user, u'XMLRPC', display_name)

        root_password = kw.get('root_password', None)
        if root_password:
            group.set_root_password(user, u'XMLRPC', root_password)

        if kw.get('add_member', None):
            username = kw.get('add_member')
            user = User.by_user_name(username)
            if user is None:
                raise BX(_(u'User does not exist %s' % username))
            if user.removed:
                raise BX(
                    _(u'Cannot add deleted user %s to group' % user.user_name))

            if user not in group.users:
                group.add_member(user,
                                 service=u'XMLRPC',
                                 agent=identity.current.user)
                mail.group_membership_notify(user,
                                             group,
                                             agent=identity.current.user,
                                             action='Added')
            else:
                raise BX(
                    _(u'User %s is already in group %s' %
                      (username, group.group_name)))

        if kw.get('remove_member', None):
            username = kw.get('remove_member')
            user = User.by_user_name(username)

            if user is None:
                raise BX(_(u'User does not exist %s' % username))

            if user not in group.users:
                raise BX(
                    _(u'No user %s in group %s' %
                      (username, group.group_name)))
            else:
                if not group.can_remove_member(identity.current.user,
                                               user.user_id):
                    raise BX(_(u'Cannot remove member'))

                groupUsers = group.users
                for usr in groupUsers:
                    if usr.user_id == user.user_id:
                        group.remove_member(user,
                                            service=u'XMLRPC',
                                            agent=identity.current.user)
                        removed = user
                        mail.group_membership_notify(
                            user,
                            group,
                            agent=identity.current.user,
                            action='Removed')
                        break

        #dummy success return value
        return ['1']
Пример #13
0
    def provision(self,
                  fqdn,
                  distro_tree_id,
                  ks_meta=None,
                  kernel_options=None,
                  kernel_options_post=None,
                  kickstart=None,
                  reboot=True):
        """
        Provisions a system with the given distro tree and options.

        The *ks_meta*, *kernel_options*, and *kernel_options_post* arguments 
        override the default values configured for the system. For example, if 
        the default kernel options for the system/distro are
        'console=ttyS0 ksdevice=eth0', and the caller passes 'ksdevice=eth1' 
        for *kernel_options*, the kernel options used will be
        'console=ttyS0 ksdevice=eth1'.

        :param distro_tree_id: numeric id of distro tree to be provisioned
        :type distro_tree_id: int
        :param ks_meta: kickstart options
        :type ks_meta: str
        :param kernel_options: kernel options for installation
        :type kernel_options: str
        :param kernel_options_post: kernel options for after installation
        :type kernel_options_post: str
        :param kickstart: complete kickstart
        :type kickstart: str
        :param reboot: whether to reboot the system after applying Cobbler changes
        :type reboot: bool

        .. versionadded:: 0.6

        .. versionchanged:: 0.6.10
           System-specific kickstart/kernel options are now obeyed.

        .. versionchanged:: 0.9
           *distro_install_name* parameter is replaced with *distro_tree_id*. 
           See :meth:`distrotrees.filter`.
        """
        system = System.by_fqdn(fqdn, identity.current.user)
        if not system.user == identity.current.user:
            raise BX(_(u'Reserve a system before provisioning'))
        distro_tree = DistroTree.by_id(distro_tree_id)

        # sanity check: does the distro tree apply to this system?
        if not system.compatible_with_distro_tree(distro_tree):
            raise BX(
                _(u'Distro tree %s cannot be provisioned on %s') %
                (distro_tree, system.fqdn))
        if not system.lab_controller:
            raise BX(_(u'System is not attached to a lab controller'))
        if not distro_tree.url_in_lab(system.lab_controller):
            raise BX(
                _(u'Distro tree %s is not available in lab %s') %
                (distro_tree, system.lab_controller))

        if identity.current.user.rootpw_expired:
            raise BX(
                _('Your root password has expired, please change or clear it in order to submit jobs.'
                  ))

        # ensure system-specific defaults are used
        # (overriden by this method's arguments)
        options = system.manual_provision_install_options(distro_tree)\
            .combined_with(InstallOptions.from_strings(
                    ks_meta or '',
                    kernel_options or '',
                    kernel_options_post or ''))
        if 'ks' not in options.kernel_options:
            rendered_kickstart = generate_kickstart(options,
                                                    distro_tree=distro_tree,
                                                    system=system,
                                                    user=identity.current.user,
                                                    kickstart=kickstart)
            options.kernel_options['ks'] = rendered_kickstart.link
        system.configure_netboot(distro_tree,
                                 options.kernel_options_str,
                                 service=u'XMLRPC')
        system.record_activity(user=identity.current.user,
                               service=u'XMLRPC',
                               action=u'Provision',
                               field=u'Distro Tree',
                               old=u'',
                               new=u'Success: %s' % distro_tree)

        if reboot:
            system.action_power(action='reboot', service=u'XMLRPC')

        return system.fqdn  # because turbogears makes us return something
Пример #14
0
    def create(self, kw):
        """
        Creates a new group.

        The *kw* argument must be an XML-RPC structure (dict)
        specifying the following keys:

            'group_name'
                 Group name (maximum 16 characters)
            'display_name'
                 Group display name
            'ldap'
                 Populate users from LDAP (True/False)

        Returns a message whether the group was successfully created or
        raises an exception on failure.

        """
        display_name = kw.get('display_name')
        group_name = kw.get('group_name')
        ldap = kw.get('ldap')
        password = kw.get('root_password')

        if ldap and not identity.current.user.is_admin():
            raise BX(_(u'Only admins can create LDAP groups'))
        try:
            group = Group.by_name(group_name)
        except NoResultFound:
            #validate
            GroupFormSchema.fields['group_name'].to_python(group_name)
            GroupFormSchema.fields['display_name'].to_python(display_name)

            group = Group()
            session.add(group)
            group.record_activity(user=identity.current.user,
                                  service=u'XMLRPC',
                                  field=u'Group',
                                  action=u'Created')
            group.display_name = display_name
            group.group_name = group_name
            group.ldap = ldap
            group.root_password = password
            user = identity.current.user

            if not ldap:
                group.user_group_assocs.append(
                    UserGroup(user=user, is_owner=True))
                group.activity.append(
                    GroupActivity(user,
                                  service=u'XMLRPC',
                                  action=u'Added',
                                  field_name=u'User',
                                  old_value=None,
                                  new_value=user.user_name))
                group.activity.append(
                    GroupActivity(user,
                                  service=u'XMLRPC',
                                  action=u'Added',
                                  field_name=u'Owner',
                                  old_value=None,
                                  new_value=user.user_name))

            if group.ldap:
                group.refresh_ldap_members()
            return 'Group created: %s.' % group_name
        else:
            raise BX(_(u'Group already exists: %s.' % group_name))