Beispiel #1
0
def provision_virt_recipe(recipe_id):
    log.debug('Attempting to provision dynamic virt guest for recipe %s', recipe_id)
    session.begin()
    try:
        recipe = Recipe.by_id(recipe_id)
        manager = dynamic_virt.VirtManager(recipe.recipeset.job.owner)
        available_flavors = manager.available_flavors()
        # We want them in order of smallest to largest, so that we can pick the
        # smallest flavor that satisfies the recipe's requirements. Sorting by RAM
        # is a decent approximation.
        possible_flavors = XmlHost.from_string(recipe.host_requires)\
            .filter_openstack_flavors(available_flavors, manager.lab_controller)
        if not possible_flavors:
            log.debug('No OpenStack flavors matched recipe %s, marking precluded',
                    recipe.id)
            recipe.virt_status = RecipeVirtStatus.precluded
            return
        possible_flavors = sorted(possible_flavors, key=lambda flavor: flavor.ram)
        flavor = possible_flavors[0]
        vm_name = '%srecipe-%s' % (
                ConfigItem.by_name(u'guest_name_prefix').current_value(u'beaker-'),
                recipe.id)
        # FIXME can we control use of virtio?
        #virtio_possible = True
        #if self.recipe.distro_tree.distro.osversion.osmajor.osmajor == "RedHatEnterpriseLinux3":
        #    virtio_possible = False
        vm = manager.create_vm(vm_name, flavor)
        vm.instance_created = datetime.utcnow()
        try:
            recipe.createRepo()
            recipe.clear_candidate_systems()
            recipe.watchdog = Watchdog()
            recipe.resource = vm
            recipe.recipeset.lab_controller = manager.lab_controller
            recipe.virt_status = RecipeVirtStatus.succeeded
            recipe.schedule()
            log.info("recipe ID %s moved from Queued to Scheduled by provision_virt_recipe" % recipe.id)
            recipe.waiting()
            recipe.provision()
            log.info("recipe ID %s moved from Scheduled to Waiting by provision_virt_recipe" % recipe.id)
        except:
            exc_type, exc_value, exc_tb = sys.exc_info()
            try:
                manager.destroy_vm(vm)
            except Exception:
                log.exception('Failed to clean up vm %s '
                        'during provision_virt_recipe, leaked!', vm.instance_id)
                # suppress this exception so the original one is not masked
            raise exc_type, exc_value, exc_tb
        session.commit()
    except Exception, e:
        log.exception('Error in provision_virt_recipe(%s)', recipe_id)
        session.rollback()
        # As an added precaution, let's try and avoid this recipe in future
        with session.begin():
            recipe = Recipe.by_id(recipe_id)
            recipe.virt_status = RecipeVirtStatus.failed
Beispiel #2
0
def provision_virt_recipes(*args):
    # We limit to labs where the tree is available by NFS because RHEV needs to 
    # use autofs to grab the images. See VirtManager.start_install.
    recipes = MachineRecipe.query\
            .join(Recipe.recipeset).join(RecipeSet.job)\
            .filter(Job.dirty_version == Job.clean_version)\
            .join(Recipe.distro_tree, DistroTree.lab_controller_assocs, LabController)\
            .filter(Recipe.status == TaskStatus.queued)\
            .filter(Recipe.virt_status == RecipeVirtStatus.possible)\
            .filter(LabController.disabled == False)\
            .filter(or_(RecipeSet.lab_controller == None,
                RecipeSet.lab_controller_id == LabController.id))\
            .filter(LabControllerDistroTree.url.like(u'nfs://%'))\
            .order_by(RecipeSet.priority.desc(), Recipe.id.asc())
    if not recipes.count():
        return False
    log.debug("Entering provision_virt_recipes")
    for recipe_id, in recipes.values(Recipe.id.distinct()):
        system_name = None
        session.begin()
        try:
            system_name = u'%srecipe_%s' % (
                    ConfigItem.by_name(u'guest_name_prefix').current_value(u'beaker_'),
                    recipe_id)
            provision_virt_recipe(system_name, recipe_id)
            session.commit()
        except needpropertyxml.NotVirtualisable:
            session.rollback()
            session.begin()
            recipe = Recipe.by_id(recipe_id)
            recipe.virt_status = RecipeVirtStatus.precluded
            session.commit()
        except VMCreationFailedException:
            session.rollback()
            session.begin()
            recipe = Recipe.by_id(recipe_id)
            recipe.virt_status = RecipeVirtStatus.skipped
            session.commit()
        except Exception, e: # This will get ovirt RequestErrors from recipe.provision()
            log.exception('Error in provision_virt_recipe(%s)', recipe_id)
            session.rollback()
            try:
                # Don't leak the vm if it was created
                if system_name:
                    with dynamic_virt.VirtManager() as manager:
                        manager.destroy_vm(system_name)
                # As an added precaution, let's try and avoid this recipe in future
                session.begin()
                recipe = Recipe.by_id(recipe_id)
                recipe.virt_status = RecipeVirtStatus.failed
                session.commit()
            except Exception:
                log.exception('Exception in exception handler :-(')
        finally:
 def run(self):
     session.begin()
     recipe = Recipe.by_id(self.recipe_id)
     self.ready_evt.set()
     self.continue_evt.wait()
     recipe.tasks[-1].stop()
     session.commit()
Beispiel #4
0
def provision_virt_recipe(system_name, recipe_id):
    recipe = Recipe.by_id(recipe_id)
    recipe.createRepo()
    # Figure out the "data centers" where we can run the recipe
    if recipe.recipeset.lab_controller:
        # First recipe of a recipeSet determines the lab_controller
        lab_controllers = [recipe.recipeset.lab_controller]
    else:
        # NB the same criteria are also expressed above
        lab_controllers = LabController.query.filter_by(disabled=False, removed=None)
        lab_controllers = needpropertyxml.apply_lab_controller_filter(
                recipe.host_requires, lab_controllers)

    lab_controllers = [lc for lc in lab_controllers.all()
            if recipe.distro_tree.url_in_lab(lc, 'nfs')]
    recipe.systems = []
    recipe.watchdog = Watchdog()
    recipe.resource = VirtResource(system_name=system_name)
    with dynamic_virt.VirtManager() as manager:
        recipe.resource.allocate(manager, lab_controllers)
    recipe.recipeset.lab_controller = recipe.resource.lab_controller
    recipe.schedule()
    log.info("recipe ID %s moved from Queued to Scheduled by provision_virt_recipe" % recipe.id)
    recipe.waiting()
    recipe.provision()
    log.info("recipe ID %s moved from Scheduled to Waiting by provision_virt_recipe" % recipe.id)
Beispiel #5
0
    def files(self, recipe_id):
        """
        Return an array of logs for the given recipe.

        :param recipe_id: id of recipe
        :type recipe_id: integer

        .. deprecated:: 0.9.4
           Use :meth:`taskactions.files() <bkr.server.task_actions.taskactions.files>` instead.
        """
        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_('Invalid recipe ID: %s' % recipe_id))
        # Build a list of logs excluding duplicate paths, to mitigate:
        # https://bugzilla.redhat.com/show_bug.cgi?id=963492
        logdicts = []
        seen_paths = set()
        for log in recipe.all_logs():
            logdict = log.dict
            # The path we care about here is the path which beaker-transfer 
            # will move the file to.
            # Don't be tempted to use os.path.join() here since log['path'] 
            # is often '/' which does not give the result you would expect.
            path = os.path.normpath('%s/%s/%s' % (logdict['filepath'],
                    logdict['path'], logdict['filename']))
            if path in seen_paths:
                logger.warn('%s contains duplicate log %s', log.parent.t_id, path)
            else:
                seen_paths.add(path)
                logdicts.append(logdict)
        return logdicts
Beispiel #6
0
    def install_start(self, recipe_id=None):
        """
        Report comencement of provisioning of a recipe's resource, extend
        first task's watchdog, and report 'Install Started' against it.
        """
        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_("Invalid Recipe ID %s" % recipe_id))

        first_task = recipe.first_task
        if not recipe.resource.install_started:
            recipe.resource.install_started = datetime.utcnow()
            # extend watchdog by 3 hours 60 * 60 * 3
            kill_time = 10800
            # XXX In future releases where 'Provisioning'
            # is a valid recipe state, we will no longer
            # need the following block.
            log.debug('Extending watchdog for %s', first_task.t_id)
            first_task.extend(kill_time)
            log.debug('Recording /start for %s', first_task.t_id)
            first_task.pass_(path=u'/start', score=0, summary=u'Install Started')
            return True
        else:
            log.debug('Already recorded /start for %s', first_task.t_id)
            return False
Beispiel #7
0
    def install_done(self, recipe_id=None, fqdn=None):
        """
        Report completion of installation with current FQDN
        """
        if not recipe_id:
            raise BX(_("No recipe id provided!"))
        if not fqdn:
            raise BX(_("No fqdn provided!"))

        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_("Invalid Recipe ID %s" % recipe_id))

        recipe.resource.install_finished = datetime.utcnow()
        # We don't want to change an existing FQDN, just set it
        # if it hasn't been set already (see BZ#879146)
        configured = recipe.resource.fqdn
        if configured is None:
            recipe.resource.fqdn = configured = fqdn
        elif configured != fqdn:
            # We use eager formatting here to make this easier to test
            log.info("Configured FQDN (%s) != reported FQDN (%s) in R:%s" %
                     (configured, fqdn, recipe_id))
        return configured
Beispiel #8
0
def provision_virt_recipes(*args):
    recipes = MachineRecipe.query\
            .join(Recipe.recipeset).join(RecipeSet.job)\
            .filter(Job.dirty_version == Job.clean_version)\
            .join(Recipe.distro_tree, DistroTree.lab_controller_assocs, LabController)\
            .filter(Recipe.status == TaskStatus.queued)\
            .filter(Recipe.virt_status == RecipeVirtStatus.possible)\
            .filter(LabController.disabled == False)\
            .filter(or_(RecipeSet.lab_controller == None,
                RecipeSet.lab_controller_id == LabController.id))\
            .order_by(RecipeSet.priority.desc(), Recipe.id.asc())
    if not recipes.count():
        return False
    log.debug("Entering provision_virt_recipes")
    for recipe_id, in recipes.values(Recipe.id.distinct()):
        session.begin()
        try:
            provision_virt_recipe(recipe_id)
            session.commit()
        except Exception, e:
            log.exception('Error in provision_virt_recipe(%s)', recipe_id)
            session.rollback()
            # As an added precaution, let's try and avoid this recipe in future
            with session.begin():
                recipe = Recipe.by_id(recipe_id)
                recipe.virt_status = RecipeVirtStatus.failed
        finally:
Beispiel #9
0
 def tearDown(self):
     admin_user = User.by_user_name(data_setup.ADMIN_USER)
     if getattr(self,'recipe_id', None):
         with session.begin():
             recipe = Recipe.by_id(self.recipe_id)
             if recipe.resource.system.open_reservation:
                 recipe.resource.release()
Beispiel #10
0
    def really_return_reservation(self, id, msg=None):
        try:
            recipe = Recipe.by_id(id)
        except InvalidRequestError:
            raise BX(_("Invalid Recipe ID %s" % id))
        recipe.return_reservation()

        flash(_(u"Successfully released reserved system for %s" % recipe.t_id))
        redirect('/jobs/mine')
Beispiel #11
0
 def extend(self, recipe_id, kill_time):
     """
     Extend recipe watchdog by kill_time seconds
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_('Invalid recipe ID: %s' % recipe_id))
     return recipe.extend(kill_time)
Beispiel #12
0
 def console_output(self, recipe_id, output_length=None, offset=None):
     """
     Get text console log output from OpenStack 
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_('Invalid recipe ID: %s' % recipe_id))
     manager = dynamic_virt.VirtManager(recipe.recipeset.job.owner)
     return manager.get_console_output(recipe.resource.instance_id, output_length)
Beispiel #13
0
 def postinstall_done(self, recipe_id=None):
     """
     Report completion of postinstallation
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_(u'Invalid Recipe ID %s' % recipe_id))
     recipe.resource.postinstall_finished = datetime.utcnow()
     return True
Beispiel #14
0
 def test_rendered_kickstart_is_deleted(self):
     with session.begin():
         self.job_to_delete.to_delete = datetime.datetime.utcnow()
         recipe = self.job_to_delete.recipesets[0].recipes[0]
         ks = RenderedKickstart(kickstart=u'This is not a real kickstart.')
         recipe.rendered_kickstart = ks
     log_delete.log_delete()
     with session.begin():
         self.assertEqual(Recipe.by_id(recipe.id).rendered_kickstart, None)
         self.assertRaises(NoResultFound, RenderedKickstart.by_id, ks.id)
Beispiel #15
0
 def to_xml(self, recipe_id=None):
     """ 
         Pass in recipe id and you'll get that recipe's xml
     """
     if not recipe_id:
         raise BX(_("No recipe id provided!"))
     try:
         recipexml = Recipe.by_id(recipe_id).to_xml().toprettyxml()
     except InvalidRequestError:
         raise BX(_("Invalid Recipe ID %s" % recipe_id))
     return recipexml
Beispiel #16
0
 def to_xml(self, recipe_id=None):
     """ 
         Pass in recipe id and you'll get that recipe's xml
     """
     if not recipe_id:
         raise BX(_("No recipe id provided!"))
     try:
         recipexml = etree.tostring(Recipe.by_id(recipe_id).to_xml(),
                                    pretty_print=True, encoding='utf8')
     except InvalidRequestError:
         raise BX(_("Invalid Recipe ID %s" % recipe_id))
     return recipexml
Beispiel #17
0
 def postinstall_done(self, recipe_id=None):
     """
     Report completion of postinstallation
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_(u'Invalid Recipe ID %s' % recipe_id))
     if not recipe.installation:
         raise BX(_('Recipe %s not provisioned yet') % recipe_id)
     recipe.installation.postinstall_finished = datetime.utcnow()
     return True
Beispiel #18
0
 def systems(self, recipe_id=None, *args, **kw):
     try:
         recipe = Recipe.by_id(recipe_id)
     except NoResultFound:
         flash(_(u"Invalid recipe id %s" % recipe_id))
         redirect(url("/recipes"))
     PDC = widgets.PaginateDataGrid.Column
     fields = [PDC(name='fqdn', getter=lambda x: x.link, title='Name'),
         PDC(name='user', getter=lambda x: x.user.email_link if x.user else None, title='User'),]
     grid = myPaginateDataGrid(fields=fields)
     return dict(title='Recipe Systems', grid=grid, list=recipe.systems,
         search_bar=None)
Beispiel #19
0
 def default(self, id):
     try:
         recipe = Recipe.by_id(id)
     except InvalidRequestError:
         flash(_(u"Invalid recipe id %s" % id))
         redirect(".")
     if recipe.is_deleted():
         flash(_(u"Invalid %s, has been deleted" % recipe.t_id))
         redirect(".")
     return dict(title   = 'Recipe',
                 recipe_widget        = self.recipe_widget,
                 recipe               = recipe)
Beispiel #20
0
 def stop(self, recipe_id, stop_type, msg=None):
     """
     Set recipe status to Completed
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_('Invalid recipe ID: %s' % recipe_id))
     if stop_type not in recipe.stop_types:
         raise BX(_('Invalid stop_type: %s, must be one of %s' %
                          (stop_type, recipe.stop_types)))
     kwargs = dict(msg = msg)
     return getattr(recipe,stop_type)(**kwargs)
Beispiel #21
0
 def stop(self, recipe_id, stop_type, msg=None):
     """
     Set recipe status to Completed
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_('Invalid recipe ID: %s' % recipe_id))
     if stop_type not in recipe.stop_types:
         raise BX(_('Invalid stop_type: %s, must be one of %s' %
                          (stop_type, recipe.stop_types)))
     kwargs = dict(msg = msg)
     return getattr(recipe,stop_type)(**kwargs)
Beispiel #22
0
 def to_xml(self, recipe_id=None):
     """ 
         Pass in recipe id and you'll get that recipe's xml
     """
     if not recipe_id:
         raise BX(_("No recipe id provided!"))
     try:
         recipexml = etree.tostring(Recipe.by_id(recipe_id).to_xml(),
                                    pretty_print=True,
                                    encoding='utf8')
     except InvalidRequestError:
         raise BX(_("Invalid Recipe ID %s" % recipe_id))
     return recipexml
Beispiel #23
0
 def systems(self, recipe_id=None, *args, **kw):
     try:
         recipe = Recipe.by_id(recipe_id)
     except NoResultFound:
         flash(_(u"Invalid recipe id %s" % recipe_id))
         redirect(url("/recipes"))
     PDC = widgets.PaginateDataGrid.Column
     fields = [PDC(name='fqdn', getter=lambda x: x.link, title='Name'),
               PDC(name='loanedto', getter=lambda x: x.loaned.user_name if x.loaned else None, title='Loaned'),
               PDC(name='user', getter=lambda x: x.user.email_link if x.user else None, title='User'),]
     grid = myPaginateDataGrid(fields=fields)
     return dict(title='Recipe Systems', grid=grid, list=recipe.systems,
         search_bar=None)
Beispiel #24
0
def provision_virt_recipe(recipe_id):
    recipe = Recipe.by_id(recipe_id)
    manager = dynamic_virt.VirtManager(recipe.recipeset.job.owner)
    available_flavors = manager.available_flavors()
    # We want them in order of smallest to largest, so that we can pick the
    # smallest flavor that satisfies the recipe's requirements. Sorting by RAM
    # is a decent approximation.
    available_flavors = sorted(available_flavors,
                               key=lambda flavor: flavor.ram)
    possible_flavors = XmlHost.from_string(recipe.host_requires)\
        .filter_openstack_flavors(available_flavors, manager.lab_controller)
    if not possible_flavors:
        log.debug('No OpenStack flavors matched recipe %s, marking precluded',
                  recipe.id)
        recipe.virt_status = RecipeVirtStatus.precluded
        return
    flavor = possible_flavors[0]
    vm_name = '%srecipe-%s' % (ConfigItem.by_name(
        u'guest_name_prefix').current_value(u'beaker-'), recipe.id)
    # FIXME can we control use of virtio?
    #virtio_possible = True
    #if self.recipe.distro_tree.distro.osversion.osmajor.osmajor == "RedHatEnterpriseLinux3":
    #    virtio_possible = False
    instance_id = manager.create_vm(vm_name, flavor)
    try:
        recipe.createRepo()
        recipe.systems = []
        recipe.watchdog = Watchdog()
        recipe.resource = VirtResource(instance_id, manager.lab_controller)
        recipe.recipeset.lab_controller = manager.lab_controller
        recipe.virt_status = RecipeVirtStatus.succeeded
        recipe.schedule()
        log.info(
            "recipe ID %s moved from Queued to Scheduled by provision_virt_recipe"
            % recipe.id)
        recipe.waiting()
        recipe.provision()
        log.info(
            "recipe ID %s moved from Scheduled to Waiting by provision_virt_recipe"
            % recipe.id)
    except:
        exc_type, exc_value, exc_tb = sys.exc_info()
        try:
            manager.destroy_vm(instance_id)
        except Exception:
            log.exception(
                'Failed to clean up instance %s '
                'during provision_virt_recipe, leaked!', instance_id)
            # suppress this exception so the original one is not masked
        raise exc_type, exc_value, exc_tb
Beispiel #25
0
 def change_files(self, recipe_id, server, basepath):
     """
     Change the server and basepath where the log files lives, Usually
      used to move from lab controller cache to archive storage.
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_('Invalid recipe ID: %s' % recipe_id))
     for mylog in recipe.all_logs():
         mylog.server = '%s/%s/' % (server, mylog.parent.filepath)
         mylog.basepath = '%s/%s/' % (basepath, mylog.parent.filepath)
     recipe.log_server = urlparse.urlparse(server)[1]
     return True
Beispiel #26
0
    def register_file(self, server, task_id, path, filename, basepath):
        """
        register file and return path to store
        """
        try:
            recipetask = RecipeTask.by_id(task_id, lockmode='update')
        except NoResultFound:
            raise BX(_('Invalid task ID: %s' % task_id))
        Recipe.by_id(recipetask.recipe_id, lockmode='update')
        if recipetask.is_finished():
            raise BX('Cannot register file for finished task %s'
                    % recipetask.t_id)
        self._check_log_limit(recipetask)

        # Add the log to the DB if it hasn't been recorded yet.
        log_recipe = LogRecipeTask.lazy_create(recipe_task_id=recipetask.id,
                                               path=path, 
                                               filename=filename,
                                              )
        log_recipe.server = server
        log_recipe.basepath = basepath
        recipetask.recipe.log_server = urlparse.urlparse(server)[1]
        return '%s' % recipetask.filepath
Beispiel #27
0
 def change_files(self, recipe_id, server, basepath):
     """
     Change the server and basepath where the log files lives, Usually
      used to move from lab controller cache to archive storage.
     """
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_('Invalid recipe ID: %s' % recipe_id))
     for mylog in recipe.all_logs():
         mylog.server = '%s/%s/' % (server, mylog.parent.filepath)
         mylog.basepath = '%s/%s/' % (basepath, mylog.parent.filepath)
     recipe.log_server = urlparse.urlparse(server)[1]
     return True
Beispiel #28
0
    def files(self, recipe_id):
        """
        Return an array of logs for the given recipe.

        :param recipe_id: id of recipe
        :type recipe_id: integer

        .. deprecated:: 0.9.4
           Use :meth:`taskactions.files` instead.
        """
        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_('Invalid recipe ID: %s' % recipe_id))
        return [log for log in recipe.all_logs]
Beispiel #29
0
    def register_file(self, server, task_id, path, filename, basepath):
        """
        register file and return path to store
        """
        try:
            recipetask = RecipeTask.by_id(task_id, lockmode='update')
        except NoResultFound:
            raise BX(_('Invalid task ID: %s' % task_id))
        Recipe.by_id(recipetask.recipe_id, lockmode='update')
        if recipetask.is_finished():
            raise BX('Cannot register file for finished task %s' %
                     recipetask.t_id)
        self._check_log_limit(recipetask)

        # Add the log to the DB if it hasn't been recorded yet.
        log_recipe = LogRecipeTask.lazy_create(
            recipe_task_id=recipetask.id,
            path=path,
            filename=filename,
        )
        log_recipe.server = server
        log_recipe.basepath = basepath
        recipetask.recipe.log_server = urlparse.urlparse(server)[1]
        return '%s' % recipetask.filepath
Beispiel #30
0
    def files(self, recipe_id):
        """
        Return an array of logs for the given recipe.

        :param recipe_id: id of recipe
        :type recipe_id: integer

        .. deprecated:: 0.9.4
           Use :meth:`taskactions.files` instead.
        """
        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_('Invalid recipe ID: %s' % recipe_id))
        return [log for log in recipe.all_logs]
Beispiel #31
0
 def default(self, id, *args, **kwargs):
     # When flask returns a 404, it falls back to here so we need to
     # raise a cherrypy 404.
     if cherrypy.request.method == 'POST':
         raise cherrypy.HTTPError(404)
     try:
         recipe = Recipe.by_id(id)
     except InvalidRequestError:
         flash(_(u"Invalid recipe id %s" % id))
         redirect(".")
     if recipe.is_deleted():
         flash(_(u"Invalid %s, has been deleted" % recipe.t_id))
         redirect(".")
     return dict(title   = 'Recipe',
                 recipe_widget        = self.recipe_widget,
                 recipe               = recipe)
Beispiel #32
0
 def default(self, id, *args, **kwargs):
     # When flask returns a 404, it falls back to here so we need to
     # raise a cherrypy 404.
     if cherrypy.request.method == 'POST':
         raise cherrypy.HTTPError(404)
     try:
         recipe = Recipe.by_id(id)
     except InvalidRequestError:
         flash(_(u"Invalid recipe id %s" % id))
         redirect(".")
     if recipe.is_deleted():
         flash(_(u"Invalid %s, has been deleted" % recipe.t_id))
         redirect(".")
     return dict(title='Recipe',
                 recipe_widget=self.recipe_widget,
                 recipe=recipe)
Beispiel #33
0
    def postreboot(self, recipe_id=None):
        # Backwards compat only, delete this after 0.10:
        # the recipe_id arg used to be hostname
        try:
            int(recipe_id)
        except ValueError:
            system = System.by_fqdn(recipe_id, identity.current.user)
            system.action_power('reboot', service=u'XMLRPC', delay=30)
            return system.fqdn

        try:
            recipe = Recipe.by_id(int(recipe_id))
        except (InvalidRequestError, NoResultFound, ValueError):
            raise BX(_('Invalid recipe ID %s') % recipe_id)
        if isinstance(recipe.resource, SystemResource):
            recipe.resource.system.action_power('reboot',
                    service=u'XMLRPC', delay=30)
        return True
Beispiel #34
0
    def postreboot(self, recipe_id=None):
        # Backwards compat only, delete this after 0.10:
        # the recipe_id arg used to be hostname
        try:
            int(recipe_id)
        except ValueError:
            system = System.by_fqdn(recipe_id, identity.current.user)
            system.action_power('reboot', service=u'XMLRPC', delay=30)
            return system.fqdn

        try:
            recipe = Recipe.by_id(int(recipe_id))
        except (InvalidRequestError, NoResultFound, ValueError):
            raise BX(_('Invalid recipe ID %s') % recipe_id)
        if isinstance(recipe.resource, SystemResource):
            recipe.resource.system.action_power('reboot',
                    service=u'XMLRPC', delay=30)
        return True
Beispiel #35
0
 def default(self, id, *args, **kwargs):
     # When flask returns a 404, it falls back to here so we need to
     # raise a cherrypy 404.
     if cherrypy.request.method == 'POST':
         raise cherrypy.HTTPError(404)
     if args:
         raise cherrypy.HTTPError(404)
     if cherrypy.request.path.endswith('/'):
         raise cherrypy.HTTPError(404)
     try:
         recipe = Recipe.by_id(id)
     except InvalidRequestError:
         flash(_(u"Invalid recipe id %s" % id))
         redirect(".")
     if recipe.is_deleted:
         flash(_(u"Invalid %s, has been deleted" % recipe.t_id))
         redirect(".")
     recipe.set_reviewed_state(identity.current.user, True)
     return dict(title   = 'Recipe',
                 recipe_widget        = self.recipe_widget,
                 recipe               = recipe)
Beispiel #36
0
    def register_file(self, server, recipe_id, path, filename, basepath):
        """
        register file and return path to store
        """
        try:
            recipe = Recipe.by_id(recipe_id, lockmode='update')
        except NoResultFound:
            raise BX(_('Invalid recipe ID: %s' % recipe_id))
        if recipe.is_finished():
            raise BX('Cannot register file for finished recipe %s'
                    % recipe.t_id)

        # Add the log to the DB if it hasn't been recorded yet.
        log_recipe = LogRecipe.lazy_create(recipe_id=recipe.id,
                                           path=path,
                                           filename=filename,
                                          )
        log_recipe.server = server
        log_recipe.basepath = basepath
        # Pull log_server out of server_url.
        recipe.log_server = urlparse.urlparse(server)[1]
        return '%s' % recipe.filepath
Beispiel #37
0
    def register_file(self, server, recipe_id, path, filename, basepath):
        """
        register file and return path to store
        """
        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_('Invalid recipe ID: %s' % recipe_id))
        if recipe.is_finished():
            raise BX('Cannot register file for finished recipe %s'
                    % recipe.t_id)

        # Add the log to the DB if it hasn't been recorded yet.
        log_recipe = LogRecipe.lazy_create(recipe_id=recipe.id,
                                           path=path,
                                           filename=filename,
                                          )
        log_recipe.server = server
        log_recipe.basepath = basepath
        # Pull log_server out of server_url.
        recipe.log_server = urlparse.urlparse(server)[1]
        return '%s' % recipe.filepath
Beispiel #38
0
 def default(self, id, *args, **kwargs):
     # When flask returns a 404, it falls back to here so we need to
     # raise a cherrypy 404.
     if cherrypy.request.method == 'POST':
         raise cherrypy.HTTPError(404)
     if args:
         raise cherrypy.HTTPError(404)
     if cherrypy.request.path.endswith('/'):
         raise cherrypy.HTTPError(404)
     try:
         recipe = Recipe.by_id(id)
     except InvalidRequestError:
         flash(_(u"Invalid recipe id %s" % id))
         redirect(".")
     if recipe.is_deleted:
         flash(_(u"Invalid %s, has been deleted" % recipe.t_id))
         redirect(".")
     if recipe.is_finished() or recipe.status == TaskStatus.reserved:
         recipe.set_reviewed_state(identity.current.user, True)
     return dict(title   = 'Recipe',
                 recipe_widget        = self.recipe_widget,
                 recipe               = recipe)
    def test_reserve_with_recipe(self):
        with session.begin():
            recipe = data_setup.create_recipe()
            job = data_setup.create_job_for_recipes([recipe])
            data_setup.mark_job_running(job)
            recipe = Recipe.by_id(recipe.id)
            fqdn = recipe.resource.system.fqdn
            user = recipe.resource.system.user
            recipe.resource.system.loaned = user
            recipe.resource.system.loan_comment = u'Amy, must I jujitsu my ma?'
        system = recipe.resource.system
        # JSON output
        json_out = run_client(['bkr', 'system-status', fqdn, '--format',
            'json'])
        json_out = loads(json_out)
        current_reservation = json_out.get('current_reservation')
        self.assertEqual(current_reservation.get('user_name'),
            unicode(system.user))
        self.assertEqual(current_reservation.get('recipe_id'), '%s' % \
            system.open_reservation.recipe.id)
        self.assertEqual(json_out.get('condition'), '%s' % system.status)

        # Human friendly output
        human_out = run_client(['bkr', 'system-status', fqdn])
        expected_out = textwrap.dedent('''\
            Condition: %s
            Current reservation:
                User: %s
                Recipe ID: %s
                Start time: %s UTC
            Current loan:
                User: %s
                Comment: Amy, must I jujitsu my ma?''' % \
            (system.status, system.user, system.open_reservation.recipe.id,
            system.open_reservation.recipe.start_time.strftime('%Y-%m-%d %H:%M:%S'),
            system.loaned))
        human_out = human_out.rstrip('\n')
        self.assertEqual(human_out, expected_out, human_out)
    def test_reserve_with_recipe(self):
        with session.begin():
            recipe = data_setup.create_recipe()
            job = data_setup.create_job_for_recipes([recipe])
            data_setup.mark_job_running(job)
            recipe = Recipe.by_id(recipe.id)
            fqdn = recipe.resource.system.fqdn
            user = recipe.resource.system.user
            recipe.resource.system.loaned = user
            recipe.resource.system.loan_comment = 'Amy, must I jujitsu my ma?'
        system = recipe.resource.system
        # JSON output
        json_out = run_client(
            ['bkr', 'system-status', fqdn, '--format', 'json'])
        json_out = loads(json_out)
        current_reservation = json_out.get('current_reservation')
        self.assertEqual(current_reservation.get('user_name'),
                         unicode(system.user))
        self.assertEqual(current_reservation.get('recipe_id'), '%s' % \
            system.open_reservation.recipe.id)
        self.assertEqual(json_out.get('condition'), '%s' % system.status)

        # Human friendly output
        human_out = run_client(['bkr', 'system-status', fqdn])
        expected_out = textwrap.dedent('''\
            Condition: %s
            Current reservation:
                User: %s
                Recipe ID: %s
                Start time: %s UTC
            Current loan:
                User: %s
                Comment: Amy, must I jujitsu my ma?''' % \
            (system.status, system.user, system.open_reservation.recipe.id,
            system.open_reservation.recipe.start_time.strftime('%Y-%m-%d %H:%M:%S'),
            system.loaned))
        human_out = human_out.rstrip('\n')
        self.assertEqual(human_out, expected_out, human_out)
Beispiel #41
0
    def install_start(self, recipe_id=None):
        """
        Records the start of a recipe's installation. The watchdog is extended 
        by 3 hours to allow the installation to complete.
        """
        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_("Invalid Recipe ID %s" % recipe_id))
        if not recipe.installation:
            raise BX(_('Recipe %s not provisioned yet') % recipe_id)

        installation = recipe.installation
        if not installation.install_started:
            installation.install_started = datetime.utcnow()
            # extend watchdog by 3 hours 60 * 60 * 3
            kill_time = 10800
            log.debug('Extending watchdog for %s', recipe.t_id)
            recipe.extend(kill_time)
            return True
        else:
            log.debug('Already recorded install_started for %s', recipe.t_id)
            return False
Beispiel #42
0
    def install_start(self, recipe_id=None):
        """
        Records the start of a recipe's installation. The watchdog is extended 
        by 3 hours to allow the installation to complete.
        """
        try:
            recipe = Recipe.by_id(recipe_id)
        except InvalidRequestError:
            raise BX(_("Invalid Recipe ID %s" % recipe_id))
        if not recipe.installation:
            raise BX(_('Recipe %s not provisioned yet') % recipe_id)

        installation = recipe.installation
        if not installation.install_started:
            installation.install_started = datetime.utcnow()
            # extend watchdog by 3 hours 60 * 60 * 3
            kill_time = 10800
            logger.debug('Extending watchdog for %s', recipe.t_id)
            recipe.extend(kill_time)
            return True
        else:
            logger.debug('Already recorded install_started for %s', recipe.t_id)
            return False
Beispiel #43
0
    def postreboot(self, recipe_id=None):
        # Backwards compat only, delete this after 0.10:
        # the recipe_id arg used to be hostname
        try:
            int(recipe_id)
        except ValueError:
            system = System.by_fqdn(recipe_id, identity.current.user)
            system.action_power('reboot', service=u'XMLRPC', delay=30)
            return system.fqdn

        try:
            recipe = Recipe.by_id(int(recipe_id))
        except (InvalidRequestError, NoResultFound, ValueError):
            raise BX(_('Invalid recipe ID %s') % recipe_id)
        if isinstance(recipe.resource, SystemResource):
            recipe.resource.system.action_power('reboot',
                    service=u'XMLRPC', delay=30)
        elif isinstance(recipe.resource, VirtResource):
            # XXX this should also be delayed 30 seconds but there is no way
            with dynamic_virt.VirtManager() as manager:
                vm = manager.api.vms.get(recipe.resource.system_name)
                vm.stop()
                vm.start()
        return True
Beispiel #44
0
 def watchdog(self, recipe_id):
     try:
         recipe = Recipe.by_id(recipe_id)
     except InvalidRequestError:
         raise BX(_('Invalid recipe ID: %s' % recipe_id))
     return recipe.status_watchdog()
Beispiel #45
0
 def parrot(self, *args, **kw):
     if 'recipe_id' in kw:
         recipe = Recipe.by_id(kw['recipe_id'])
         return recipe.all_tasks
Beispiel #46
0
def main(*args):
    parser = optparse.OptionParser('usage: %prog [options]',
                                   description=__description__,
                                   version=__version__)
    parser.add_option('-u',
                      '--user',
                      metavar='USERNAME',
                      help='The user we are creating a kickstart for',
                      default='admin')
    parser.add_option('-r',
                      '--recipe-id',
                      metavar='ID',
                      help='Recreate kickstart based on recipe ID')
    parser.add_option('-d',
                      '--distro-tree-id',
                      metavar='ID',
                      help='Recreate kickstart based on distro ID')
    parser.add_option('-t',
                      '--template-dir',
                      metavar='DIR',
                      help='Retrieve templates from DIR')
    parser.add_option('-f',
                      '--system',
                      metavar='FQDN',
                      help='Generate kickstart for system identified by FQDN')
    parser.add_option('-m',
                      '--ks-meta',
                      metavar='OPTIONS',
                      help='Kickstart meta data')
    parser.add_option('-p',
                      '--kernel-options-post',
                      metavar='OPTIONS',
                      help='Kernel options post')
    options, args = parser.parse_args(*args)
    ks_meta = options.ks_meta
    koptions_post = options.kernel_options_post
    template_dir = options.template_dir
    if template_dir:
        add_to_template_searchpath(template_dir)

    if not options.recipe_id:
        if not options.distro_tree_id and not options.system:
            parser.error(
                'Must specify either a recipe or a distro tree and system')
        elif not options.distro_tree_id:
            parser.error(
                'Must specify a distro tree id when passing in a system')
        elif not options.system:
            parser.error('Must specify a system when not specifying a recipe')

    load_config_or_exit()
    with session.begin():
        user = User.by_user_name(options.user)
        ks_appends = None
        recipe = None
        distro_tree = None
        system = None
        install_options = None

        if options.distro_tree_id:
            try:
                distro_tree = DistroTree.by_id(options.distro_tree_id)
            except NoResultFound:
                raise RuntimeError("Distro tree id '%s' does not exist" %
                                   options.distro_tree_id)
        if options.system:
            fqdn = options.system
            try:
                system = System.by_fqdn(fqdn, user)
            except NoResultFound:
                raise RuntimeError("System '%s' does not exist" % fqdn)

            if distro_tree and not options.recipe_id:
                install_options = system.manual_provision_install_options(distro_tree)\
                    .combined_with(InstallOptions.from_strings(ks_meta, None, koptions_post))

        if options.recipe_id:
            try:
                recipe = Recipe.by_id(options.recipe_id)
            except NoResultFound:
                raise RuntimeError("Recipe id '%s' does not exist" %
                                   options.recipe_id)
            if not recipe.resource and not options.system:
                raise RuntimeError('Recipe must have (or had) a resource'
                                   ' assigned to it')
            if not system:
                system = getattr(recipe.resource, 'system', None)
            if not distro_tree:
                distro_tree = recipe.distro_tree

            install_options = InstallOptions.reduce(
                chain([global_install_options()],
                      distro_tree.install_options(),
                      system.install_options(distro_tree), [
                          recipe.generated_install_options(),
                          InstallOptions.from_strings(
                              recipe.ks_meta, recipe.kernel_options,
                              recipe.kernel_options_post),
                          InstallOptions.from_strings(ks_meta, None,
                                                      koptions_post)
                      ]))

            ks_appends = [ks_append.ks_append for ks_append \
                          in recipe.ks_appends]
            user = recipe.recipeset.job.owner

        # Render the kickstart
        rendered_kickstart = generate_kickstart(install_options,
                                                distro_tree=distro_tree,
                                                system=system,
                                                user=user,
                                                recipe=recipe,
                                                ks_appends=ks_appends)
        kickstart = rendered_kickstart.kickstart

    print kickstart
Beispiel #47
0
 def _to_python(self, value, state):
     try:
         recipe = Recipe.by_id(value)
     except NoResultFound:
         raise Invalid('Invalid recipe', value, state)
     return recipe
Beispiel #48
0
def _get_recipe_by_id(id):
    """Get recipe by id, reporting HTTP 404 if the recipe is not found"""
    try:
        return Recipe.by_id(id)
    except NoResultFound:
        raise NotFound404('Recipe not found')
Beispiel #49
0
def main(*args):
    parser = optparse.OptionParser('usage: %prog [options]',
        description=__description__,
        version=__version__)
    parser.add_option('-u', '--user', metavar='USERNAME',
        help='The user we are creating a kickstart for', default='admin')
    parser.add_option('-r', '--recipe-id', metavar='ID',
        help='Recreate kickstart based on recipe ID')
    parser.add_option('-d', '--distro-tree-id', metavar='ID',
        help='Recreate kickstart based on distro ID')
    parser.add_option('-t', '--template-dir', metavar='DIR',
        help='Retrieve templates from DIR')
    parser.add_option('-f', '--system', metavar='FQDN',
        help='Generate kickstart for system identified by FQDN')
    parser.add_option('-m', '--ks-meta', metavar='OPTIONS', default='',
        help='Kickstart meta data')
    parser.add_option('-p', '--kernel-options-post', metavar='OPTIONS', default='',
        help='Kernel options post')
    options, args = parser.parse_args(*args)
    ks_meta = options.ks_meta.decode(sys.getfilesystemencoding())
    koptions_post = options.kernel_options_post.decode(sys.getfilesystemencoding())
    template_dir = options.template_dir
    if template_dir:
        add_to_template_searchpath(template_dir)

    if not options.recipe_id:
        if not options.distro_tree_id and not options.system:
            parser.error('Must specify either a recipe or a distro tree and system')
        elif not options.distro_tree_id:
            parser.error('Must specify a distro tree id when passing in a system')
        elif not options.system:
            parser.error('Must specify a system when not specifying a recipe')

    load_config_or_exit()
    with session.begin():
        user = User.by_user_name(options.user.decode(sys.getfilesystemencoding()))
        ks_appends = None
        recipe = None
        distro_tree = None
        system = None
        install_options = None

        if options.distro_tree_id:
            try:
                distro_tree = DistroTree.by_id(options.distro_tree_id)
            except NoResultFound:
                raise RuntimeError("Distro tree id '%s' does not exist" % options.distro_tree_id)
        if options.system:
            fqdn = options.system.decode(sys.getfilesystemencoding())
            try:
                system = System.by_fqdn(fqdn, user)
            except DatabaseLookupError:
                raise RuntimeError("System '%s' does not exist" % fqdn)

            if distro_tree and not options.recipe_id:
                install_options = system.manual_provision_install_options(distro_tree)\
                    .combined_with(InstallOptions.from_strings(ks_meta, None, koptions_post))

        if options.recipe_id:
            try:
                recipe = Recipe.by_id(options.recipe_id)
            except NoResultFound:
                raise RuntimeError("Recipe id '%s' does not exist" % options.recipe_id)
            if not recipe.resource and not options.system:
                raise RuntimeError('Recipe must have (or had) a resource'
                                   ' assigned to it')
            if not system:
                system = getattr(recipe.resource, 'system', None)
            if not distro_tree:
                distro_tree = recipe.distro_tree

            sources = []
            # if distro_tree is specified, distro_tree overrides recipe
            osmajor = distro_tree.distro.osversion.osmajor.osmajor if distro_tree else recipe.installation.osmajor
            osminor = distro_tree.distro.osversion.osminor if distro_tree else recipe.installation.osminor
            variant = distro_tree.variant if distro_tree else recipe.installation.variant
            arch = distro_tree.arch if distro_tree else recipe.installation.arch

            sources.append(install_options_for_distro(osmajor, osminor, variant, arch))
            if distro_tree:
                sources.append(distro_tree.install_options())
            sources.extend(system.install_options(arch, osmajor, osminor))
            sources.append(recipe.generated_install_options())
            sources.append(InstallOptions.from_strings(recipe.ks_meta,
                                                       recipe.kernel_options, recipe.kernel_options_post))
            sources.append(InstallOptions.from_strings(ks_meta, None, koptions_post))

            install_options = InstallOptions.reduce(sources)

            ks_appends = [ks_append.ks_append for ks_append \
                          in recipe.ks_appends]
            user = recipe.recipeset.job.owner

        # Render the kickstart
        installation = recipe.installation if recipe and recipe.installation else \
            FakeInstallation(distro_tree.distro.osversion.osmajor.osmajor,
                             distro_tree.distro.osversion.osminor,
                             distro_tree.distro.name,
                             distro_tree.variant,
                             distro_tree.arch,
                             distro_tree.url_in_lab(lab_controller=system.lab_controller))
        rendered_kickstart = generate_kickstart(install_options=install_options,
                                                distro_tree=distro_tree,
                                                installation=installation,
                                                system=system,
                                                user=user,
                                                recipe=recipe,
                                                ks_appends=ks_appends)
        kickstart = rendered_kickstart.kickstart

    print kickstart
Beispiel #50
0
def provision_virt_recipe(recipe_id):
    log.debug('Attempting to provision dynamic virt guest for recipe %s',
              recipe_id)
    session.begin()
    try:
        recipe = Recipe.by_id(recipe_id)
        job_owner = recipe.recipeset.job.owner
        manager = dynamic_virt.VirtManager(job_owner)
        available_flavors = manager.available_flavors()
        # We want them in order of smallest to largest, so that we can pick the
        # smallest flavor that satisfies the recipe's requirements. Sorting by RAM
        # is a decent approximation.
        possible_flavors = XmlHost.from_string(recipe.host_requires)\
            .filter_openstack_flavors(available_flavors, manager.lab_controller)
        if not possible_flavors:
            log.info(
                'No OpenStack flavors matched recipe %s, marking precluded',
                recipe.id)
            recipe.virt_status = RecipeVirtStatus.precluded
            return
        # cheapest flavor has the smallest disk and ram
        # id guarantees consistency of our results
        flavor = min(possible_flavors,
                     key=lambda flavor: (flavor.ram, flavor.disk, flavor.id))
        vm_name = '%srecipe-%s' % (ConfigItem.by_name(
            u'guest_name_prefix').current_value(u'beaker-'), recipe.id)
        log.debug('Creating VM named %s as flavor %s', vm_name, flavor)
        vm = manager.create_vm(vm_name, flavor)
        vm.instance_created = datetime.utcnow()
        try:
            recipe.createRepo()
            recipe.clear_candidate_systems()
            recipe.watchdog = Watchdog()
            recipe.resource = vm
            recipe.recipeset.lab_controller = manager.lab_controller
            recipe.virt_status = RecipeVirtStatus.succeeded
            recipe.schedule()
            log.info(
                "recipe ID %s moved from Queued to Scheduled by provision_virt_recipe",
                recipe.id)
            recipe.waiting()
            recipe.provision()
            log.info(
                "recipe ID %s moved from Scheduled to Waiting by provision_virt_recipe",
                recipe.id)
        except:
            exc_type, exc_value, exc_tb = sys.exc_info()
            try:
                manager.destroy_vm(vm)
            except Exception:
                log.exception(
                    'Failed to clean up VM %s during provision_virt_recipe, leaked!',
                    vm.instance_id)
                # suppress this exception so the original one is not masked
            raise exc_type, exc_value, exc_tb
        session.commit()
    except Exception as e:
        log.exception('Error in provision_virt_recipe(%s)', recipe_id)
        session.rollback()
        # As an added precaution, let's try and avoid this recipe in future
        with session.begin():
            recipe = Recipe.by_id(recipe_id)
            recipe.virt_status = RecipeVirtStatus.failed
    finally:
        session.close()