コード例 #1
0
ファイル: mail.py プロジェクト: joyxu/beaker
def system_problem_report(system, description, recipe=None, reporter=None):
    if reporter is not None:
        sender = _sender_details(reporter)
    else:
        sender = config.get('beaker_email')
    if not sender:
        log.warning("beaker_email not defined in app.cfg; unable to send mail")
        return
    body = [_(u'A Beaker user has reported a problem with system \n%s <%s>.')
            % (system.fqdn, absolute_url('/view/%s' % system.fqdn)), '']
    if reporter is not None:
        body.append(_(u'Reported by: %s') % reporter.display_name)
    if recipe is not None:
        body.append(_(u'Related to: %s <%s>') % (recipe.t_id,
                absolute_url('/recipes/%s' % recipe.id)))
    body.extend(['', unicode(_(u'Problem description:')), description])
    headers=[('X-Beaker-Notification', 'system-problem'),
        ('X-Beaker-System', system.fqdn),
        ('X-Lender', system.lender or ''),
        ('X-Owner', system.owner),
        ('X-Location', system.location or ''),
        ('X-Lab-Controller', system.lab_controller or ''),
        ('X-Vendor', system.vendor or ''),
        ('X-Type', system.type)]
    arch_headers = [('X-Arch', arch) for arch in system.arch]
    headers.extend(arch_headers)
    cc = []
    if reporter is not None:
        cc.append(reporter.email_address)
    cc.extend(system.cc)
    send_mail(sender, system.owner.email_address,
            _(u'Problem reported for %s') % system.fqdn, '\n'.join(body),
            cc=cc, headers=headers)
コード例 #2
0
 def test_delayed_jobs(self):
     with session.begin():
         # Create a queued job that was submitted a long time ago
         recipe = data_setup.create_recipe()
         job = data_setup.create_job_for_recipes([recipe])
         job.owner = self.user
         data_setup.mark_job_queued(job)
         job.recipesets[0].queue_time = datetime.utcnow() - timedelta(days=self.delayed_job_age)
         # create a job with two recipes, one Queued and one Scheduled
         # which was submitted a long time ago
         queued_recipe = data_setup.create_recipe()
         scheduled_recipe = data_setup.create_recipe()
         job_with_multiple_recipes = data_setup.create_job_for_recipes([queued_recipe, scheduled_recipe])
         job_with_multiple_recipes.owner = self.user
         # mark recipe Queued
         queued_recipe.process()
         queued_recipe.queue()
         # mark recipe Scheduled
         scheduled_recipe.process()
         scheduled_recipe.queue()
         scheduled_recipe.schedule()
         data_setup.mark_job_queued(job_with_multiple_recipes)
         job_with_multiple_recipes.recipesets[0].queue_time = datetime.utcnow()\
             - timedelta(days=self.delayed_job_age)
         # create a new submmited job for just now
         recently_submmited_job = data_setup.create_job_for_recipes([recipe])
         recently_submmited_job.owner = self.user
         data_setup.mark_job_queued(recently_submmited_job)
     beaker_usage = BeakerUsage(self.user, self.reservation_expiry, self.reservation_length,
                            self.waiting_recipe_age, self.delayed_job_age)
     delayed_jobs = beaker_usage.delayed_jobs()
     self.assertEqual(len(delayed_jobs), 2)
     self.assertEqual(absolute_url('/jobs/%s' % job.id), delayed_jobs[0][1])
     self.assertEqual(absolute_url('/jobs/%s' % job_with_multiple_recipes.id), delayed_jobs[1][1])
コード例 #3
0
def system_problem_report(system, description, recipe=None, reporter=None):
    if reporter is not None:
        sender = _sender_details(reporter)
    else:
        sender = config.get('beaker_email')
    if not sender:
        log.warning("beaker_email not defined in app.cfg; unable to send mail")
        return
    body = [_(u'A Beaker user has reported a problem with system \n%s <%s>.')
            % (system.fqdn, absolute_url('/view/%s' % system.fqdn)), '']
    if reporter is not None:
        body.append(_(u'Reported by: %s') % reporter.display_name)
    if recipe is not None:
        body.append(_(u'Related to: %s <%s>') % (recipe.t_id,
                absolute_url('/recipes/%s' % recipe.id)))
    body.extend(['', unicode(_(u'Problem description:')), description])
    headers=[('X-Beaker-Notification', 'system-problem'),
        ('X-Beaker-System', system.fqdn),
        ('X-Lender', system.lender or ''),
        ('X-Owner', system.owner),
        ('X-Location', system.location or ''),
        ('X-Lab-Controller', system.lab_controller or ''),
        ('X-Vendor', system.vendor or ''),
        ('X-Type', system.type)]
    arch_headers = [('X-Arch', arch) for arch in system.arch]
    headers.extend(arch_headers)
    cc = []
    if reporter is not None:
        cc.append(reporter.email_address)
    cc.extend(system.cc)
    send_mail(sender, system.owner.email_address,
            _(u'Problem reported for %s') % system.fqdn, '\n'.join(body),
            cc=cc, headers=headers)
コード例 #4
0
ファイル: mail.py プロジェクト: joyxu/beaker
def broken_system_notify(system, reason, recipe=None):
    if system.owner.notify_broken_system:
        sender = config.get('beaker_email')
        if not sender:
            log.warning("beaker_email not defined in app.cfg; unable to send mail")
            return
        body = [_(u'Beaker has automatically marked system \n%s <%s> \nas broken, due to:')
                % (system.fqdn, absolute_url('/view/%s' % system.fqdn)), '', reason, '',
                unicode(_(u'Please investigate this error and take appropriate action.')), '']
        if recipe:
            body.extend([_(u'Failure occurred in %s <%s>') % (recipe.t_id,
                    absolute_url('/recipes/%s' % recipe.id)), ''])
        if system.power:
            body.extend([_(u'Power type: %s') % system.power.power_type.name,
                         _(u'Power address: %s') % system.power.power_address,
                         _(u'Power id: %s') % system.power.power_id])
        send_mail(sender, system.owner.email_address,
                _(u'System %s automatically marked broken') % system.fqdn,
                '\n'.join(body),
                cc=system.cc,
                headers=[('X-Beaker-Notification', 'system-broken'),
                         ('X-Beaker-System', system.fqdn),
                         ('X-Lender', system.lender or ''),
                         ('X-Owner', system.owner),
                         ('X-Location', system.location or ''),
                         ('X-Lab-Controller', system.lab_controller or ''),
                         ('X-Vendor', system.vendor or ''),
                         ('X-Type', system.type)] +
                        [('X-Arch', arch) for arch in system.arch])
コード例 #5
0
def broken_system_notify(system, reason, recipe=None):
    sender = config.get('beaker_email')
    if not sender:
        log.warning("beaker_email not defined in app.cfg; unable to send mail")
        return
    body = [_(u'Beaker has automatically marked system \n%s <%s> \nas broken, due to:')
            % (system.fqdn, absolute_url('/view/%s' % system.fqdn)), '', reason, '',
            unicode(_(u'Please investigate this error and take appropriate action.')), '']
    if recipe:
        body.extend([_(u'Failure occurred in %s <%s>') % (recipe.t_id,
                absolute_url('/recipes/%s' % recipe.id)), ''])
    if system.power:
        body.extend([_(u'Power type: %s') % system.power.power_type.name,
                     _(u'Power address: %s') % system.power.power_address,
                     _(u'Power id: %s') % system.power.power_id])
    send_mail(sender, system.owner.email_address,
            _(u'System %s automatically marked broken') % system.fqdn,
            '\n'.join(body),
            cc=system.cc,
            headers=[('X-Beaker-Notification', 'system-broken'),
                     ('X-Beaker-System', system.fqdn),
                     ('X-Lender', system.lender or ''),
                     ('X-Owner', system.owner),
                     ('X-Location', system.location or ''),
                     ('X-Lab-Controller', system.lab_controller or ''),
                     ('X-Vendor', system.vendor or ''),
                     ('X-Type', system.type)] +
                    [('X-Arch', arch) for arch in system.arch])
コード例 #6
0
ファイル: identity.py プロジェクト: xhernandez/beaker
 def __init__(self, message=None):
     self._message = message or _(u'Please log in')
     self.args = [self._message]
     if cherrypy.request.method not in ('GET', 'HEAD'):
         # Other HTTP methods cannot be safely redirected through the login
         # form, so we will just show a 403.
         self.status = 403
     else:
         self.status = 302
         if current.anonymous:
             forward_url = cherrypy.request.path
             if cherrypy.request.query_string:
                 forward_url += '?%s' % cherrypy.request.query_string
             self.urls = [absolute_url('/login', forward_url=forward_url)]
         else:
             self.urls = [absolute_url('/forbidden', reason=message)]
コード例 #7
0
ファイル: identity.py プロジェクト: ShaolongHu/beaker
 def __init__(self, message=None):
     self._message = message or _(u'Please log in')
     self.args = [self._message]
     if cherrypy.request.method not in ('GET', 'HEAD'):
         # Other HTTP methods cannot be safely redirected through the login 
         # form, so we will just show a 403.
         self.status = 403
     else:
         self.status = 302
         if current.anonymous:
             forward_url = cherrypy.request.path
             if cherrypy.request.query_string:
                 forward_url += '?%s' % cherrypy.request.query_string
             self.urls = [absolute_url('/login', forward_url=forward_url)]
         else:
             self.urls = [absolute_url('/forbidden', reason=message)]
コード例 #8
0
ファイル: reserve_workflow.py プロジェクト: ShaolongHu/beaker
def doit():
    distro_trees = []
    for id in request.form.getlist('distro_tree_id'):
        try:
            distro_trees.append(DistroTree.by_id(id))
        except NoResultFound:
            raise BadRequest400('Distro tree %r does not exist' % id)
    job_details = {}
    job_details['pick'] = request.form.get('pick') or 'auto'
    if job_details['pick'] == 'fqdn':
        try:
            job_details['system'] = System.by_fqdn(request.form.get('system'),
                    identity.current.user)
        except NoResultFound:
            raise BadRequest400('System %s not found' % request.form.get('system'))
    elif job_details['pick'] == 'lab':
        try:
            job_details['lab'] = LabController.by_name(request.form.get('lab'))
        except NoResultFound:
            raise BadRequest400('Lab controller %s not found' % request.form.get('lab'))
    days = int(request.form.get('reserve_days') or DEFAULT_RESERVE_DAYS)
    days = min(days, MAX_DAYS_PROVISION)
    job_details['reservetime'] = days * 24 * 60 * 60
    job_details['whiteboard'] = request.form.get('whiteboard')
    job_details['ks_meta'] = request.form.get('ks_meta')
    job_details['koptions'] = request.form.get('koptions')
    job_details['koptions_post'] = request.form.get('koptions_post')
    with convert_internal_errors():
        job = Job.provision_system_job(distro_trees, **job_details)
    return 'Created %s' % job.t_id, 201, [('Location', absolute_url('/jobs/%s' % job.id))]
コード例 #9
0
ファイル: rdf.py プロジェクト: pombredanne/beaker-1
def describe_device_class(device_class, graph):
    concept = URIRef(
            absolute_url('/devices/%s' % urllib.quote(device_class.device_class.encode('utf8'), ''))
            + '#class')
    graph.add((concept, RDF.type, INV.DeviceClass))
    graph.add((concept, RDFS.label, Literal(device_class.device_class)))
    return concept
コード例 #10
0
ファイル: rdf.py プロジェクト: pombredanne/beaker-1
def describe_arch(arch, graph):
    concept = URIRef(
            absolute_url('/arch/%s' % urllib.quote(arch.arch.encode('utf8'), ''))
            + '#arch')
    graph.add((concept, RDF.type, INV.Arch))
    graph.add((concept, RDFS.label, Literal(arch.arch)))
    return concept
コード例 #11
0
ファイル: rdf.py プロジェクト: pombredanne/beaker-1
def describe_key(key, graph):
    concept = URIRef(
            absolute_url('/keys/%s' % urllib.quote(key.key_name.encode('utf8'), ''))
            + '#key')
    graph.add((concept, RDF.type, RDF.Property))
    graph.add((concept, RDFS.label, Literal(key.key_name)))
    return concept
コード例 #12
0
ファイル: rdf.py プロジェクト: pombredanne/beaker-1
def describe_bus_type(bus_type, graph):
    concept = URIRef(
            absolute_url('/devices/bus/%s' % urllib.quote(bus_type.encode('utf8'), ''))
            + '#bus')
    graph.add((concept, RDF.type, INV.BusType))
    graph.add((concept, RDFS.label, Literal(bus_type)))
    return concept
コード例 #13
0
ファイル: mail.py プロジェクト: ShaolongHu/beaker
def system_loan_request(system, message, requester, requestee_email):
    sender = _sender_details(requester)
    body = [
        _(
            u"A Beaker user has requested you loan them the system\n%s <%s>.\n"
            "Here is a copy of their request:\n"
            "%s\n Requested by: %s"
        )
        % (system.fqdn, absolute_url("/view/%s" % system.fqdn), message, requester.display_name),
        "",
    ]

    headers = [
        ("X-Beaker-Notification", "loan-request"),
        ("X-Beaker-System", system.fqdn),
        ("X-Lender", system.lender or ""),
        ("X-Owner", system.owner),
        ("X-Location", system.location or ""),
        ("X-Lab-Controller", system.lab_controller or ""),
        ("X-Vendor", system.vendor or ""),
        ("X-Type", system.type),
    ]

    arch_headers = [("X-Arch", arch) for arch in system.arch]
    headers.extend(arch_headers)
    cc = [requester.email_address] + system.cc
    send_mail(sender, requestee_email, _(u"Loan request for %s") % system.fqdn, "\n".join(body), cc=cc, headers=headers)
コード例 #14
0
ファイル: rdf.py プロジェクト: sibiaoluo/beaker
def describe_arch(arch, graph):
    concept = URIRef(
            absolute_url('/arch/%s' % urllib.quote(arch.arch.encode('utf8'), ''))
            + '#arch')
    graph.add((concept, RDF.type, INV.Arch))
    graph.add((concept, RDFS.label, Literal(arch.arch)))
    return concept
コード例 #15
0
ファイル: pools.py プロジェクト: ShaolongHu/beaker
def create_pool():
    """
    Creates a new system pool in Beaker. The request must be 
    :mimetype:`application/x-www-form-urlencoded` or 
    :mimetype:`application/json`.

    :jsonparam string name: Name for the system pool.
    :jsonparam string description: Description of the system pool.
    :jsonparam object owner: JSON object containing a ``user_name`` key or
      ``group_name`` key identifying the owner for the system pool.

    :status 201: The system pool was successfully created.
    """
    owner = None
    description = None
    u = identity.current.user
    if request.json:
        if 'name' not in request.json:
            raise BadRequest400('Missing pool name key')
        new_name = request.json['name']
        if 'owner' in request.json:
            owner = request.json['owner']
        if 'description' in request.json:
            description = request.json['description']
    elif request.form:
        if 'name' not in request.form:
            raise BadRequest400('Missing pool name parameter')
        new_name = request.form['name']
        if 'owner' in request.form:
            owner = request.form['owner']
        if 'description' in request.form:
            description = request.form['description']
    else:
        raise UnsupportedMediaType415
    with convert_internal_errors():
        if SystemPool.query.filter(SystemPool.name == new_name).count() != 0:
            raise Conflict409('System pool with name %r already exists' %
                              new_name)
        pool = SystemPool(name=new_name, description=description)
        session.add(pool)
        if owner:
            owner, owner_type = _get_owner(owner)
            if owner_type == 'user':
                pool.owning_user = owner
            else:
                pool.owning_group = owner
        else:
            pool.owning_user = u
        # new systems pool are visible to everybody by default
        pool.access_policy = SystemAccessPolicy()
        pool.access_policy.add_rule(SystemPermission.view, everybody=True)
        pool.record_activity(user=u,
                             service=u'HTTP',
                             action=u'Created',
                             field=u'Pool',
                             new=unicode(pool))
    response = jsonify(pool.__json__())
    response.status_code = 201
    response.headers.add('Location', absolute_url(pool.href))
    return response
コード例 #16
0
ファイル: rdf.py プロジェクト: sibiaoluo/beaker
def describe_key(key, graph):
    concept = URIRef(
            absolute_url('/keys/%s' % urllib.quote(key.key_name.encode('utf8'), ''))
            + '#key')
    graph.add((concept, RDF.type, RDF.Property))
    graph.add((concept, RDFS.label, Literal(key.key_name)))
    return concept
コード例 #17
0
ファイル: rdf.py プロジェクト: sibiaoluo/beaker
def describe_bus_type(bus_type, graph):
    concept = URIRef(
            absolute_url('/devices/bus/%s' % urllib.quote(bus_type.encode('utf8'), ''))
            + '#bus')
    graph.add((concept, RDF.type, INV.BusType))
    graph.add((concept, RDFS.label, Literal(bus_type)))
    return concept
コード例 #18
0
ファイル: installation.py プロジェクト: beaker-project/beaker
 def link(self):
     if self.url:
         return self.url
     assert self.id is not None, 'not flushed?'
     url = absolute_url('/kickstart/%s' % self.id, scheme='http',
                        labdomain=True)
     return url
コード例 #19
0
ファイル: rdf.py プロジェクト: sibiaoluo/beaker
def describe_device_class(device_class, graph):
    concept = URIRef(
            absolute_url('/devices/%s' % urllib.quote(device_class.device_class.encode('utf8'), ''))
            + '#class')
    graph.add((concept, RDF.type, INV.DeviceClass))
    graph.add((concept, RDFS.label, Literal(device_class.device_class)))
    return concept
コード例 #20
0
ファイル: mail.py プロジェクト: walbon/beaker
def system_loan_request(system, message, requester, requestee_email):
    sender = _sender_details(requester)
    body = [
        _(u'A Beaker user has requested you loan them the system\n%s <%s>.\n'
          'Here is a copy of their request:\n'
          '%s\n Requested by: %s') %
        (system.fqdn, absolute_url(
            '/view/%s' % system.fqdn), message, requester.display_name), ''
    ]

    headers = [('X-Beaker-Notification', 'loan-request'),
               ('X-Beaker-System', system.fqdn),
               ('X-Lender', system.lender or ''), ('X-Owner', system.owner),
               ('X-Location', system.location or ''),
               ('X-Lab-Controller', system.lab_controller or ''),
               ('X-Vendor', system.vendor or ''), ('X-Type', system.type)]

    arch_headers = [('X-Arch', arch) for arch in system.arch]
    headers.extend(arch_headers)
    cc = [requester.email_address] + system.cc
    send_mail(sender,
              requestee_email,
              _(u'Loan request for %s') % system.fqdn,
              '\n'.join(body),
              cc=cc,
              headers=headers)
コード例 #21
0
ファイル: rdf.py プロジェクト: sibiaoluo/beaker
def describe_user(user, graph):
    concept = URIRef(
            absolute_url('/users/%s' % urllib.quote(user.user_name.encode('utf8'), ''))
            + '#user')
    graph.add((concept, RDF.type, FOAF.User))
    graph.add((concept, FOAF.name, Literal(user.display_name)))
    graph.add((concept, FOAF.mbox, URIRef('mailto:' + user.email_address)))
    return concept
コード例 #22
0
ファイル: group.py プロジェクト: joyxu/beaker
def groups_mine():
    """
    Redirect for compatibility.
    """
    return flask_redirect(
        absolute_url('/groups/',
                     q='member.user_name:%s' %
                     identity.current.user.user_name))
コード例 #23
0
ファイル: installation.py プロジェクト: joyxu/beaker
 def link(self):
     if self.url:
         return self.url
     assert self.id is not None, 'not flushed?'
     url = absolute_url('/kickstart/%s' % self.id,
                        scheme='http',
                        labdomain=True)
     return url
コード例 #24
0
def failed_recipes(job):
    msg = "JobID: %s Status: %s Result: %s <%s>\n" % \
             (job.id, job.status, job.result, absolute_url('/jobs/%s' % job.id))
    for recipeset in job.recipesets:
        if recipeset.is_failed():
            msg = "%s\tRecipeSetID: %s\n" % (msg, recipeset.id)
            for recipe in recipeset.recipes:
                if recipe.is_failed():
                    msg = "%s\t\tRecipeID: %s Arch: %s System: %s Distro: %s Status: %s Result: %s <%s>\n" \
                           % (msg, recipe.id, recipe.distro_tree.arch, recipe.resource, recipe.distro_tree.distro,
                              recipe.status, recipe.result, absolute_url('/recipes/%s' % recipe.id))
                    for task in recipe.tasks:
                        if task.is_failed():
                            msg = "%s\t\t\tTaskID: %s TaskName: %s StartTime: %s Duration: %s Status: %s Result: %s\n" \
                               % (msg, task.id, task.name, task.start_time, task.duration,
                                  task.status, task.result)
    return msg
コード例 #25
0
    def _create_delayed_job(self):
        recipe = data_setup.create_recipe()
        job = data_setup.create_job_for_recipes([recipe])
        job.owner = self.user
        data_setup.mark_job_queued(job)
        job.recipesets[0].queue_time = datetime.utcnow() - timedelta(days=self.delayed_job_age)
        email_content = u"""
The following jobs you submitted to %s have been queued for more than %s days. Please cancel
them if they are no longer relevant, or perhaps arrange a loan of an appropriate system or systems

Start time               Delayed Job
%s      %s
"""     % (absolute_url('/'),
           self.delayed_job_age,
           job.recipesets[0].queue_time.strftime('%Y-%m-%d %H:%M:%S'),
           absolute_url('/jobs/%s') % job.id)
        return email_content
コード例 #26
0
def failed_recipes(job):
    msg = "JobID: %s Status: %s Result: %s <%s>\n" % \
             (job.id, job.status, job.result, absolute_url('/jobs/%s' % job.id))
    for recipeset in job.recipesets:
        if recipeset.is_failed():
            msg = "%s\tRecipeSetID: %s\n" % ( msg, recipeset.id )
            for recipe in recipeset.recipes:
                if recipe.is_failed():
                    msg = "%s\t\tRecipeID: %s Arch: %s System: %s Distro: %s Status: %s Result: %s <%s>\n" \
                           % (msg, recipe.id, recipe.distro_tree.arch, recipe.resource, recipe.distro_tree.distro,
                              recipe.status, recipe.result, absolute_url('/recipes/%s' % recipe.id))
                    for task in recipe.tasks:
                        if task.is_failed():
                            msg = "%s\t\t\tTaskID: %s TaskName: %s StartTime: %s Duration: %s Status: %s Result: %s\n" \
                               % (msg, task.id, task.name, task.start_time, task.duration,
                                  task.status, task.result)
    return msg
コード例 #27
0
ファイル: rdf.py プロジェクト: pombredanne/beaker-1
def describe_user(user, graph):
    concept = URIRef(
            absolute_url('/users/%s' % urllib.quote(user.user_name.encode('utf8'), ''))
            + '#user')
    graph.add((concept, RDF.type, FOAF.User))
    graph.add((concept, FOAF.name, Literal(user.display_name)))
    graph.add((concept, FOAF.mbox, URIRef('mailto:' + user.email_address)))
    return concept
コード例 #28
0
ファイル: test_mail.py プロジェクト: walbon/beaker
    def _create_delayed_job(self):
        recipe = data_setup.create_recipe()
        job = data_setup.create_job_for_recipes([recipe])
        job.owner = self.user
        data_setup.mark_job_queued(job)
        job.recipesets[0].queue_time = datetime.utcnow() - timedelta(days=self.delayed_job_age)
        email_content = u"""
The following jobs you submitted to %s have been queued for more than %s days. Please cancel
them if they are no longer relevant, or perhaps arrange a loan of an appropriate system or systems

Start time               Delayed Job
%s      %s
"""     % (absolute_url('/'),
           self.delayed_job_age,
           job.recipesets[0].queue_time.strftime('%Y-%m-%d %H:%M:%S'),
           absolute_url('/jobs/%s') % job.id)
        return email_content
コード例 #29
0
ファイル: group.py プロジェクト: joyxu/beaker
def create_group():
    """
    Creates a new user group in Beaker. The request must be 
    :mimetype:`application/json`.

    :jsonparam string group_name: Symbolic name for the group.
    :jsonparam string display_name: Human-friendly display name for the group.
    :jsonparam string description: Description of the group.
    :jsonparam string root_password: Optional root password for group jobs.
      If this is not set, group jobs will use the root password preferences of 
      the job submitter.
    :jsonparam string membership_type: Specifies how group membership is populated.
      Possible values are:

      * normal: Group is initially empty, members are explicitly added and removed by
        group owner.
      * ldap: Membership is populated from the LDAP group with the same group name.
      * inverted: Group contains all Beaker users *except* users who have been explicitly
        excluded by the group owner.

    :status 201: The group was successfully created.
    """
    user = identity.current.user
    data = read_json_request(request)
    if 'group_name' not in data:
        raise BadRequest400('Missing group_name key')
    if 'display_name' not in data:
        raise BadRequest400('Missing display_name key')
    # for backwards compatibility
    if data.pop('ldap', False):
        data['membership_type'] = 'ldap'
    try:
        Group.by_name(data['group_name'])
    except NoResultFound:
        pass
    else:
        raise Conflict409("Group '%s' already exists" % data['group_name'])
    with convert_internal_errors():
        group = Group.lazy_create(group_name=data['group_name'])
        group.display_name = data['display_name']
        group.description = data.get('description')
        group.root_password = data.get('root_password')
        session.add(group)
        group.record_activity(user=user,
                              service=u'HTTP',
                              field=u'Group',
                              action=u'Created')
        if data.get('membership_type'):
            group.membership_type = GroupMembershipType.from_string(
                data['membership_type'])
        if group.membership_type == GroupMembershipType.ldap:
            group.refresh_ldap_members()
        else:  # LDAP groups don't have any owners
            group.add_member(user, is_owner=True, agent=identity.current.user)
    response = jsonify(group.__json__())
    response.status_code = 201
    response.headers.add('Location', absolute_url(group.href))
    return response
コード例 #30
0
def update_group(group_name):
    """
    Updates attributes of an existing group. The request body must be a JSON
    object containing one or more of the following keys.

    :jsonparam string group_name: New name for the group.
    :jsonparam string display_name: Display name of the group.
    :jsonparam string description: Description of the group.
    :jsonparam string root_password: Optional password. Can be an empty string.
      If empty, group jobs will use the root password preferences of the job submitter.
    :jsonparam string membership_type: New membership type for the group.
      See `POST /groups/` for more information.

    :status 200: Group was updated.
    :status 400: Invalid data was given.
    """
    group = _get_group_by_name(group_name)
    if not group.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit group')
    data = read_json_request(request)
    with convert_internal_errors():
        user = identity.current.user
        renamed = False
        if 'group_name' in data:
            new_name = data['group_name']
            if new_name != group.group_name:
                if Group.query.filter(Group.group_name == new_name).count():
                    raise Conflict409('Group %s already exists' % new_name)
                group.set_name(user, u'HTTP', new_name)
                renamed = True
        if 'display_name' in data:
            new_display_name = data['display_name']
            if new_display_name != group.display_name:
                group.set_display_name(user, u'HTTP', new_display_name)
        if 'description' in data:
            new_description = data['description']
            if new_description != group.description:
                group.set_description(user, u'HTTP', new_description)
        if 'root_password' in data:
            new_root_password = data['root_password']
            if new_root_password != group.root_password:
                group.set_root_password(user, u'HTTP', new_root_password)
        # for backwards compatibility
        if data.pop('ldap', False):
            data['membership_type'] = 'ldap'
        if 'membership_type' in data:
            new_type = GroupMembershipType.from_string(
                    data['membership_type'])
            if (new_type == GroupMembershipType.ldap and not
                group.can_edit_ldap(user)):
                raise BadRequest400('Cannot edit LDAP group %s' % group)
            if new_type != group.membership_type:
                group.membership_type = new_type
    response = jsonify(group.to_json())
    if renamed:
        response.headers.add('Location', absolute_url(group.href))
    return response
コード例 #31
0
ファイル: group.py プロジェクト: qhsong/beaker
def update_group(group_name):
    """
    Updates attributes of an existing group. The request body must be a JSON
    object containing one or more of the following keys.

    :jsonparam string group_name: New name for the group.
    :jsonparam string display_name: Display name of the group.
    :jsonparam string description: Description of the group.
    :jsonparam string root_password: Optional password. Can be an empty string.
      If empty, group jobs will use the root password preferences of the job submitter.
    :jsonparam string membership_type: New membership type for the group.
      See `POST /groups/` for more information.

    :status 200: Group was updated.
    :status 400: Invalid data was given.
    """
    group = _get_group_by_name(group_name)
    if not group.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit group')
    data = read_json_request(request)
    with convert_internal_errors():
        user = identity.current.user
        renamed = False
        if 'group_name' in data:
            new_name = data['group_name']
            if new_name != group.group_name:
                if Group.query.filter(Group.group_name == new_name).count():
                    raise Conflict409('Group %s already exists' % new_name)
                group.set_name(user, u'HTTP', new_name)
                renamed = True
        if 'display_name' in data:
            new_display_name = data['display_name']
            if new_display_name != group.display_name:
                group.set_display_name(user, u'HTTP', new_display_name)
        if 'description' in data:
            new_description = data['description']
            if new_description != group.description:
                group.set_description(user, u'HTTP', new_description)
        if 'root_password' in data:
            new_root_password = data['root_password']
            if new_root_password != group.root_password:
                group.set_root_password(user, u'HTTP', new_root_password)
        # for backwards compatibility
        if data.pop('ldap', False):
            data['membership_type'] = 'ldap'
        if 'membership_type' in data:
            new_type = GroupMembershipType.from_string(
                    data['membership_type'])
            if (new_type == GroupMembershipType.ldap and not
                group.can_edit_ldap(user)):
                raise BadRequest400('Cannot edit LDAP group %s' % group)
            if new_type != group.membership_type:
                group.membership_type = new_type
    response = jsonify(group.to_json())
    if renamed:
        response.headers.add('Location', absolute_url(group.href))
    return response
コード例 #32
0
ファイル: flask_util.py プロジェクト: beaker-project/beaker
 def wrapper(*args, **kwds):
     if not identity.current.user:
         if request.method in ['GET', 'HEAD'] and not request_wants_json():
             forward_url = request.path
             if request.query_string:
                 forward_url += '?' + request.query_string
             return redirect(absolute_url('/login', forward_url=forward_url))
         raise Unauthorised401("Authenticated user required")
     return f(*args, **kwds)
コード例 #33
0
def create_pool():
    """
    Creates a new system pool in Beaker. The request must be 
    :mimetype:`application/x-www-form-urlencoded` or 
    :mimetype:`application/json`.

    :jsonparam string name: Name for the system pool.
    :jsonparam string description: Description of the system pool.
    :jsonparam object owner: JSON object containing a ``user_name`` key or
      ``group_name`` key identifying the owner for the system pool.

    :status 201: The system pool was successfully created.
    """
    owner = None
    description = None
    u = identity.current.user
    if request.json:
        if 'name' not in request.json:
            raise BadRequest400('Missing pool name key')
        new_name = request.json['name']
        if 'owner' in request.json:
            owner =  request.json['owner']
        if 'description' in request.json:
            description = request.json['description']
    elif request.form:
        if 'name' not in request.form:
            raise BadRequest400('Missing pool name parameter')
        new_name = request.form['name']
        if 'owner' in request.form:
            owner =  request.form['owner']
        if 'description' in request.form:
            description = request.form['description']
    else:
        raise UnsupportedMediaType415
    with convert_internal_errors():
        if SystemPool.query.filter(SystemPool.name == new_name).count() != 0:
            raise Conflict409('System pool with name %r already exists' % new_name)
        pool = SystemPool(name=new_name, description=description)
        session.add(pool)
        if owner:
            owner, owner_type = _get_owner(owner)
            if owner_type == 'user':
                pool.owning_user = owner
            else:
                pool.owning_group = owner
        else:
            pool.owning_user = u
        # new systems pool are visible to everybody by default
        pool.access_policy = SystemAccessPolicy()
        pool.access_policy.add_rule(SystemPermission.view, everybody=True)
        pool.record_activity(user=u, service=u'HTTP',
                     action=u'Created', field=u'Pool',
                     new=unicode(pool))
    response = jsonify(pool.__json__())
    response.status_code = 201
    response.headers.add('Location', absolute_url(pool.href))
    return response
コード例 #34
0
def create_group():
    """
    Creates a new user group in Beaker. The request must be 
    :mimetype:`application/json`.

    :jsonparam string group_name: Symbolic name for the group.
    :jsonparam string display_name: Human-friendly display name for the group.
    :jsonparam string description: Description of the group.
    :jsonparam string root_password: Optional root password for group jobs.
      If this is not set, group jobs will use the root password preferences of 
      the job submitter.
    :jsonparam string membership_type: Specifies how group membership is populated.
      Possible values are:

      * normal: Group is initially empty, members are explicitly added and removed by
        group owner.
      * ldap: Membership is populated from the LDAP group with the same group name.
      * inverted: Group contains all Beaker users *except* users who have been explicitly
        excluded by the group owner.

    :status 201: The group was successfully created.
    """
    user = identity.current.user
    data = read_json_request(request)
    if 'group_name' not in data:
        raise BadRequest400('Missing group_name key')
    if 'display_name' not in data:
        raise BadRequest400('Missing display_name key')
    # for backwards compatibility
    if data.pop('ldap', False):
        data['membership_type'] = 'ldap'
    try:
        Group.by_name(data['group_name'])
    except NoResultFound:
        pass
    else:
        raise Conflict409("Group '%s' already exists" % data['group_name'])
    with convert_internal_errors():
        group = Group.lazy_create(group_name=data['group_name'])
        group.display_name = data['display_name']
        group.description = data.get('description')
        group.root_password = data.get('root_password')
        session.add(group)
        group.record_activity(user=user, service=u'HTTP',
                field=u'Group', action=u'Created')
        if data.get('membership_type'):
            group.membership_type = GroupMembershipType.from_string(
                data['membership_type'])
        if group.membership_type == GroupMembershipType.ldap:
            group.refresh_ldap_members()
        else: # LDAP groups don't have any owners
            group.add_member(user, is_owner=True, agent=identity.current.user)
    response = jsonify(group.__json__())
    response.status_code = 201
    response.headers.add('Location', absolute_url(group.href))
    return response
コード例 #35
0
ファイル: pools.py プロジェクト: ShaolongHu/beaker
def update_pool(pool_name):
    """
    Updates attributes of an existing system pool. The request body must be a JSON 
    object containing one or more of the following keys.

    :param pool_name: System pool's name.
    :jsonparam string name: New name for the system pool.
    :jsonparam string description: Description of the system pool.
    :jsonparam object owner: JSON object containing a ``user_name`` key or
      ``group_name`` key identifying the new owner for the system pool.
    :status 200: System pool was updated.
    :status 400: Invalid data was given.
    """
    pool = _get_pool_by_name(pool_name)
    if not pool.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit system pool')
    data = read_json_request(request)

    # helper for recording activity below
    def record_activity(field, old, new, action=u'Changed'):
        pool.record_activity(user=identity.current.user,
                             service=u'HTTP',
                             action=action,
                             field=field,
                             old=old,
                             new=new)

    with convert_internal_errors():
        renamed = False
        if 'name' in data:
            new_name = data['name']
            if new_name != pool.name:
                if SystemPool.query.filter(
                        SystemPool.name == new_name).count():
                    raise Conflict409('System pool %s already exists' %
                                      new_name)
                record_activity(u'Name', pool.name, new_name)
                pool.name = new_name
                renamed = True
        if 'description' in data:
            new_description = data['description']
            if new_description != pool.description:
                record_activity(u'Description', pool.description,
                                new_description)
                pool.description = new_description
        if 'owner' in data:
            new_owner, owner_type = _get_owner(data['owner'])
            if owner_type == 'user':
                pool.change_owner(user=new_owner)
            else:
                pool.change_owner(group=new_owner)

    response = jsonify(pool.__json__())
    if renamed:
        response.headers.add('Location', absolute_url(pool.href))
    return response
コード例 #36
0
 def wrapper(*args, **kwds):
     if not identity.current.user:
         if request.method in ['GET', 'HEAD'] and not request_wants_json():
             forward_url = request.path
             if request.query_string:
                 forward_url += '?' + request.query_string
             return redirect(absolute_url('/login',
                                          forward_url=forward_url))
         raise Unauthorised401("Authenticated user required")
     return f(*args, **kwds)
コード例 #37
0
ファイル: mail.py プロジェクト: ShaolongHu/beaker
def broken_system_notify(system, reason, recipe=None):
    sender = config.get("beaker_email")
    if not sender:
        log.warning("beaker_email not defined in app.cfg; unable to send mail")
        return
    body = [
        _(u"Beaker has automatically marked system \n%s <%s> \nas broken, due to:")
        % (system.fqdn, absolute_url("/view/%s" % system.fqdn)),
        "",
        reason,
        "",
        unicode(_(u"Please investigate this error and take appropriate action.")),
        "",
    ]
    if recipe:
        body.extend([_(u"Failure occurred in %s <%s>") % (recipe.t_id, absolute_url("/recipes/%s" % recipe.id)), ""])
    if system.power:
        body.extend(
            [
                _(u"Power type: %s") % system.power.power_type.name,
                _(u"Power address: %s") % system.power.power_address,
                _(u"Power id: %s") % system.power.power_id,
            ]
        )
    send_mail(
        sender,
        system.owner.email_address,
        _(u"System %s automatically marked broken") % system.fqdn,
        "\n".join(body),
        cc=system.cc,
        headers=[
            ("X-Beaker-Notification", "system-broken"),
            ("X-Beaker-System", system.fqdn),
            ("X-Lender", system.lender or ""),
            ("X-Owner", system.owner),
            ("X-Location", system.location or ""),
            ("X-Lab-Controller", system.lab_controller or ""),
            ("X-Vendor", system.vendor or ""),
            ("X-Type", system.type),
        ]
        + [("X-Arch", arch) for arch in system.arch],
    )
コード例 #38
0
ファイル: mail.py プロジェクト: ShaolongHu/beaker
def system_problem_report(system, description, recipe=None, reporter=None):
    if reporter is not None:
        sender = _sender_details(reporter)
    else:
        sender = config.get("beaker_email")
    if not sender:
        log.warning("beaker_email not defined in app.cfg; unable to send mail")
        return
    body = [
        _(u"A Beaker user has reported a problem with system \n%s <%s>.")
        % (system.fqdn, absolute_url("/view/%s" % system.fqdn)),
        "",
    ]
    if reporter is not None:
        body.append(_(u"Reported by: %s") % reporter.display_name)
    if recipe is not None:
        body.append(_(u"Related to: %s <%s>") % (recipe.t_id, absolute_url("/recipes/%s" % recipe.id)))
    body.extend(["", unicode(_(u"Problem description:")), description])
    headers = [
        ("X-Beaker-Notification", "system-problem"),
        ("X-Beaker-System", system.fqdn),
        ("X-Lender", system.lender or ""),
        ("X-Owner", system.owner),
        ("X-Location", system.location or ""),
        ("X-Lab-Controller", system.lab_controller or ""),
        ("X-Vendor", system.vendor or ""),
        ("X-Type", system.type),
    ]
    arch_headers = [("X-Arch", arch) for arch in system.arch]
    headers.extend(arch_headers)
    cc = []
    if reporter is not None:
        cc.append(reporter.email_address)
    cc.extend(system.cc)
    send_mail(
        sender,
        system.owner.email_address,
        _(u"Problem reported for %s") % system.fqdn,
        "\n".join(body),
        cc=cc,
        headers=headers,
    )
コード例 #39
0
ファイル: rdf.py プロジェクト: pombredanne/beaker-1
def describe_system(system, graph):
    """
    Appends an RDF description of a system to the given graph.
    """
    concept = URIRef(absolute_url(system.href) + '#system')
    graph.add((concept, RDF.type, INV.System))
    graph.add((concept, INV.fqdn, Literal(system.fqdn)))
    if system.lab_controller:
        graph.add((concept, INV.controlledBy,
                describe_lab_controller(system.lab_controller, graph)))
    if system.vendor:
        graph.add((concept, INV.vendor, Literal(system.vendor)))
    if system.model:
        graph.add((concept, INV.model, Literal(system.model)))
    if system.location:
        graph.add((concept, INV.location, Literal(system.location)))
    if system.mac_address:
        graph.add((concept, INV.macAddress, Literal(system.mac_address)))
    if system.owner:
        graph.add((concept, INV.owner, describe_user(system.owner, graph)))
    for arch in system.arch:
        graph.add((concept, INV.supportsArch, describe_arch(arch, graph)))
    if system.memory:
        graph.add((concept, INV.memory, Literal(system.memory)))
    if system.numa:
        graph.add((concept, INV.numaNodes, Literal(system.numa.nodes)))
    if system.cpu:
        if system.cpu.vendor:
            graph.add((concept, INV.cpuVendor, Literal(system.cpu.vendor)))
        if system.cpu.model_name:
            graph.add((concept, INV.cpuModelName, Literal(system.cpu.model_name)))
        if system.cpu.family:
            graph.add((concept, INV.cpuFamilyId, Literal(system.cpu.family)))
        if system.cpu.model:
            graph.add((concept, INV.cpuModelId, Literal(system.cpu.model)))
        if system.cpu.stepping:
            graph.add((concept, INV.cpuStepping, Literal(system.cpu.stepping)))
        if system.cpu.speed:
            graph.add((concept, INV.cpuSpeed, Literal(Decimal(str(system.cpu.speed)))))
        if system.cpu.processors:
            graph.add((concept, INV.cpuCount, Literal(system.cpu.processors)))
        if system.cpu.cores:
            graph.add((concept, INV.cpuCoreCount, Literal(system.cpu.cores)))
        if system.cpu.sockets:
            graph.add((concept, INV.cpuSocketCount, Literal(system.cpu.sockets)))
        if system.cpu.hyper:
            graph.add((concept, INV.cpuHyperthreading, Literal(system.cpu.hyper)))
        for flag in system.cpu.flags:
            graph.add((concept, INV.cpuFlag, Literal(flag.flag)))
    for device in system.devices:
        graph.add((concept, INV.hasDevice, describe_device(device, graph)))
    for kv in chain(system.key_values_int, system.key_values_string):
        if kv.key: # ugh
            graph.add((concept, describe_key(kv.key, graph), Literal(kv.key_value)))
コード例 #40
0
ファイル: rdf.py プロジェクト: sibiaoluo/beaker
def describe_system(system, graph):
    """
    Appends an RDF description of a system to the given graph.
    """
    concept = URIRef(absolute_url(system.href) + '#system')
    graph.add((concept, RDF.type, INV.System))
    graph.add((concept, INV.fqdn, Literal(system.fqdn)))
    if system.lab_controller:
        graph.add((concept, INV.controlledBy,
                describe_lab_controller(system.lab_controller, graph)))
    if system.vendor:
        graph.add((concept, INV.vendor, Literal(system.vendor)))
    if system.model:
        graph.add((concept, INV.model, Literal(system.model)))
    if system.location:
        graph.add((concept, INV.location, Literal(system.location)))
    if system.mac_address:
        graph.add((concept, INV.macAddress, Literal(system.mac_address)))
    if system.owner:
        graph.add((concept, INV.owner, describe_user(system.owner, graph)))
    for arch in system.arch:
        graph.add((concept, INV.supportsArch, describe_arch(arch, graph)))
    if system.memory:
        graph.add((concept, INV.memory, Literal(system.memory)))
    if system.numa:
        graph.add((concept, INV.numaNodes, Literal(system.numa.nodes)))
    if system.cpu:
        if system.cpu.vendor:
            graph.add((concept, INV.cpuVendor, Literal(system.cpu.vendor)))
        if system.cpu.model_name:
            graph.add((concept, INV.cpuModelName, Literal(system.cpu.model_name)))
        if system.cpu.family:
            graph.add((concept, INV.cpuFamilyId, Literal(system.cpu.family)))
        if system.cpu.model:
            graph.add((concept, INV.cpuModelId, Literal(system.cpu.model)))
        if system.cpu.stepping:
            graph.add((concept, INV.cpuStepping, Literal(system.cpu.stepping)))
        if system.cpu.speed:
            graph.add((concept, INV.cpuSpeed, Literal(Decimal(str(system.cpu.speed)))))
        if system.cpu.processors:
            graph.add((concept, INV.cpuCount, Literal(system.cpu.processors)))
        if system.cpu.cores:
            graph.add((concept, INV.cpuCoreCount, Literal(system.cpu.cores)))
        if system.cpu.sockets:
            graph.add((concept, INV.cpuSocketCount, Literal(system.cpu.sockets)))
        if system.cpu.hyper:
            graph.add((concept, INV.cpuHyperthreading, Literal(system.cpu.hyper)))
        for flag in system.cpu.flags:
            graph.add((concept, INV.cpuFlag, Literal(flag.flag)))
    for device in system.devices:
        graph.add((concept, INV.hasDevice, describe_device(device, graph)))
    for kv in chain(system.key_values_int, system.key_values_string):
        if kv.key: # ugh
            graph.add((concept, describe_key(kv.key, graph), Literal(kv.key_value)))
コード例 #41
0
def get_labcontrollers():
    """Returns a JSON collection of all labcontrollers defined in Beaker."""
    labcontrollers = LabController.query.order_by(LabController.fqdn).all()
    if request_wants_json():
        return jsonify(entries=labcontrollers)
    can_edit = identity.current.user is not None and identity.current.user.is_admin()
    return render_tg_template('bkr.server.templates.labcontrollers', {
        'title': 'Lab Controllers',
        'labcontrollers': labcontrollers,
        'labcontrollers_url': absolute_url('/labcontrollers/'),
        'can_edit': can_edit,
    })
コード例 #42
0
ファイル: usage_reminder.py プロジェクト: omps/beaker
 def delayed_jobs(self):
     """
     Get Delayed Jobs
     """
     query = Job.query.filter(Job.owner == self.user)\
         .join(Job.recipesets)\
         .filter(and_(RecipeSet.queue_time <= (datetime.utcnow() - timedelta(days=self.delayed_job_age)),
                 RecipeSet.status == TaskStatus.queued))\
         .group_by(Job.id)\
         .values(func.min(RecipeSet.queue_time), Job.id)
     return [(queue_time, absolute_url('/jobs/%s' % job_id))
             for queue_time, job_id in query]
コード例 #43
0
def get_labcontrollers():
    """Returns a JSON collection of all labcontrollers defined in Beaker."""
    labcontrollers = LabController.query.order_by(LabController.fqdn).all()
    if request_wants_json():
        return jsonify(entries=labcontrollers)
    can_edit = identity.current.user is not None and identity.current.user.is_admin()
    return render_tg_template('bkr.server.templates.labcontrollers', {
        'title': 'Lab Controllers',
        'labcontrollers': labcontrollers,
        'labcontrollers_url': absolute_url('/labcontrollers/'),
        'can_edit': can_edit,
    })
コード例 #44
0
 def delayed_jobs(self):
     """
     Get Delayed Jobs
     """
     query = Job.query.filter(Job.owner == self.user)\
         .join(Job.recipesets)\
         .filter(and_(RecipeSet.queue_time <= (datetime.utcnow() - timedelta(days=self.delayed_job_age)),
                 RecipeSet.status == TaskStatus.queued))\
         .group_by(Job.id)\
         .values(func.min(RecipeSet.queue_time), Job.id)
     return [(queue_time, absolute_url('/jobs/%s' % job_id))
             for queue_time, job_id in query]
コード例 #45
0
    def _create_expiring_reservation(self):
        recipe = data_setup.create_recipe_reservation(self.user, u'/distribution/reservesys',
                                                      (self.reservation_expiry - 1) * 3600)
        email_content = u"""
Your reservations of the following systems in %s are going to expire within %s hours.
If you wish to ensure you retain the contents of these systems, please extend your reservation.

Expiry Date              FQDN
%s      %s
"""     % (absolute_url('/'),
           self.reservation_expiry,
           recipe.watchdog.kill_time.strftime('%Y-%m-%d %H:%M:%S'),
           recipe.resource.fqdn)
        return email_content
コード例 #46
0
ファイル: test_mail.py プロジェクト: walbon/beaker
    def _create_expiring_reservation(self):
        recipe = data_setup.create_recipe_reservation(self.user, u'/distribution/reservesys',
                                                      (self.reservation_expiry - 1) * 3600)
        email_content = u"""
Your reservations of the following systems in %s are going to expire within %s hours.
If you wish to ensure you retain the contents of these systems, please extend your reservation.

Expiry Date              FQDN
%s      %s
"""     % (absolute_url('/'),
           self.reservation_expiry,
           recipe.watchdog.kill_time.strftime('%Y-%m-%d %H:%M:%S'),
           recipe.resource.fqdn)
        return email_content
コード例 #47
0
def get_group_by_id_or_name():
    """
    Created for backwards compatibility. Will redirect to /groups/<group_name>.

    :queryparam group_id: Group's id.
    :queryparam group_name: Group's name.
    """
    if 'group_id' in request.args:
        with convert_internal_errors():
            group = Group.by_id(request.args['group_id'])
    elif 'group_name' in request.args:
        group = _get_group_by_name(request.args['group_name'])
    else:
        raise NotFound404
    return flask_redirect(absolute_url(group.href))
コード例 #48
0
ファイル: group.py プロジェクト: joyxu/beaker
def get_group_by_id_or_name():
    """
    Created for backwards compatibility. Will redirect to /groups/<group_name>.

    :queryparam group_id: Group's id.
    :queryparam group_name: Group's name.
    """
    if 'group_id' in request.args:
        with convert_internal_errors():
            group = Group.by_id(request.args['group_id'])
    elif 'group_name' in request.args:
        group = _get_group_by_name(request.args['group_name'])
    else:
        raise NotFound404
    return flask_redirect(absolute_url(group.href))
コード例 #49
0
    def test_send_usage_reminder(self):
        with session.begin():
            email_content = self._create_expiring_reservation()
            email_content += self._create_open_reservation()
            email_content += self._create_delayed_job()

        beaker_usage = BeakerUsage(self.user, self.reservation_expiry,
                                   self.reservation_length,
                                   self.waiting_recipe_age,
                                   self.delayed_job_age)
        current_date = datetime.utcnow().strftime("%Y-%m-%d")
        data = {
            'user_name': self.user.user_name,
            'current_date': current_date,
            'beaker_fqdn': absolute_url('/'),
            'reservation_expiry': self.reservation_expiry,
            'reservation_length': self.reservation_length,
            'waiting_recipe_age': self.waiting_recipe_age,
            'delayed_job_age': self.delayed_job_age,
            'expiring_reservations': beaker_usage.expiring_reservations(),
            'open_reservations': beaker_usage.open_in_demand_systems(),
            'delayed_jobs': beaker_usage.delayed_jobs()
        }

        mail_capture_thread.start_capturing()
        with session.begin():
            bkr.server.mail.send_usage_reminder(self.user, data)
        captured_mails = mail_capture_thread.stop_capturing()
        self.assertEqual(len(captured_mails), 1)
        sender, rcpts, raw_msg = captured_mails[0]
        self.assertEqual(rcpts, [self.user.email_address])
        msg = email.message_from_string(raw_msg)
        self.assertEqual(msg['To'], self.user.email_address)
        self.assertTrue(
            msg['Subject'], '[Beaker] Usage report for %s (%s)' %
            (self.user.user_name, current_date))
        expected_mail_body = u"""=========
[Beaker] Usage report for %s (%s)
=========

Hi %s,
%s
=========""" % (self.user.user_name, current_date, self.user.user_name,
                email_content)
        actual_mail_body = msg.get_payload(decode=True)
        self.assertEqual(actual_mail_body, expected_mail_body)
        self.assertEqual(msg['X-Beaker-Notification'], 'usage-report')
コード例 #50
0
def update_pool(pool_name):
    """
    Updates attributes of an existing system pool. The request body must be a JSON 
    object containing one or more of the following keys.

    :param pool_name: System pool's name.
    :jsonparam string name: New name for the system pool.
    :jsonparam string description: Description of the system pool.
    :jsonparam object owner: JSON object containing a ``user_name`` key or
      ``group_name`` key identifying the new owner for the system pool.
    :status 200: System pool was updated.
    :status 400: Invalid data was given.
    """
    pool = _get_pool_by_name(pool_name)
    if not pool.can_edit(identity.current.user):
        raise Forbidden403('Cannot edit system pool')
    data = read_json_request(request)
    # helper for recording activity below
    def record_activity(field, old, new, action=u'Changed'):
        pool.record_activity(user=identity.current.user, service=u'HTTP',
                action=action, field=field, old=old, new=new)
    with convert_internal_errors():
        renamed = False
        if 'name' in data:
            new_name = data['name']
            if new_name != pool.name:
                if SystemPool.query.filter(SystemPool.name == new_name).count():
                    raise Conflict409('System pool %s already exists' % new_name)
                record_activity(u'Name', pool.name, new_name)
                pool.name = new_name
                renamed = True
        if 'description' in data:
            new_description = data['description']
            if new_description != pool.description:
                record_activity(u'Description', pool.description, new_description)
                pool.description = new_description
        if 'owner' in data:
            new_owner, owner_type = _get_owner(data['owner'])
            if owner_type == 'user':
                pool.change_owner(user=new_owner)
            else:
                pool.change_owner(group=new_owner)

    response = jsonify(pool.__json__())
    if renamed:
        response.headers.add('Location', absolute_url(pool.href))
    return response
コード例 #51
0
ファイル: reserve_workflow.py プロジェクト: cezidev/beaker
def doit():
    distro_trees = []
    for id in request.form.getlist('distro_tree_id'):
        try:
            distro_trees.append(DistroTree.by_id(id))
        except NoResultFound:
            raise BadRequest400('Distro tree %r does not exist' % id)
    job_details = {}
    job_details['pick'] = request.form.get('pick') or 'auto'
    system_choice = 'any system'
    if job_details['pick'] == 'fqdn':
        try:
            job_details['system'] = System.by_fqdn(request.form.get('system'),
                                                   identity.current.user)
            system_choice = 'a specific system'
        except DatabaseLookupError:
            raise BadRequest400('System %s not found' %
                                request.form.get('system'))
    elif job_details['pick'] == 'lab':
        try:
            job_details['lab'] = LabController.by_name(request.form.get('lab'))
            system_choice = 'any lab system'
        except NoResultFound:
            raise BadRequest400('Lab controller %s not found' %
                                request.form.get('lab'))
    reservetime = int(
        request.form.get('reserve_duration') or DEFAULT_RESERVE_SECONDS)
    if reservetime > MAX_SECONDS_PROVISION:
        raise BadRequest400(
            'Reservation time exceeds maximum time of %s hours' %
            MAX_HOURS_PROVISION)
    job_details['reservetime'] = reservetime
    job_details['whiteboard'] = request.form.get('whiteboard')
    if not job_details['whiteboard']:
        job_details['whiteboard'] = (
            "Reserve Workflow provision of distro %s on %s for %d seconds" %
            (request.form.get('distro'), system_choice,
             job_details['reservetime']))

    job_details['ks_meta'] = request.form.get('ks_meta')
    job_details['koptions'] = request.form.get('koptions')
    job_details['koptions_post'] = request.form.get('koptions_post')
    with convert_internal_errors():
        job = Job.provision_system_job(distro_trees, **job_details)
    return 'Created %s' % job.t_id, 201, [('Location',
                                           absolute_url('/jobs/%s' % job.id))]
コード例 #52
0
ファイル: test_mail.py プロジェクト: beaker-project/beaker
    def test_send_usage_reminder(self):
        with session.begin():
            email_content = self._create_expiring_reservation()
            email_content += self._create_open_reservation()
            email_content += self._create_delayed_job()

        beaker_usage = BeakerUsage(self.user, self.reservation_expiry, self.reservation_length,
                                   self.waiting_recipe_age, self.delayed_job_age)
        current_date = datetime.utcnow().strftime("%Y-%m-%d")
        data = {
            'user_name': self.user.user_name,
            'current_date': current_date,
            'beaker_fqdn': absolute_url('/'),
            'reservation_expiry': self.reservation_expiry,
            'reservation_length': self.reservation_length,
            'waiting_recipe_age': self.waiting_recipe_age,
            'delayed_job_age': self.delayed_job_age,
            'expiring_reservations': beaker_usage.expiring_reservations(),
            'open_reservations': beaker_usage.open_in_demand_systems(),
            'delayed_jobs': beaker_usage.delayed_jobs()
        }

        mail_capture_thread.start_capturing()
        with session.begin():
            bkr.server.mail.send_usage_reminder(self.user, data)
        captured_mails = mail_capture_thread.stop_capturing()
        self.assertEqual(len(captured_mails),1)
        sender, rcpts, raw_msg = captured_mails[0]
        self.assertEqual(rcpts, [self.user.email_address])
        msg = email.message_from_string(raw_msg)
        self.assertEqual(msg['To'], self.user.email_address)
        self.assertTrue(msg['Subject'], '[Beaker] Usage report for %s (%s)' % (self.user.user_name, current_date))
        expected_mail_body = u"""=========
[Beaker] Usage report for %s (%s)
=========

Hi %s,
%s
=========""" % (self.user.user_name,
                current_date,
                self.user.user_name,
                email_content)
        actual_mail_body = msg.get_payload(decode=True)
        self.assertEqual(actual_mail_body, expected_mail_body)
        self.assertEqual(msg['X-Beaker-Notification'], 'usage-report')
コード例 #53
0
def generate_image(delete=True):
    f = tempfile.NamedTemporaryFile(suffix='.beaker-ipxe-image', delete=delete)
    log.debug('Generating image in %s', f.name)
    subprocess.check_call(['mformat', '-i', f.name, '-C', '-t', '4', '-h', '64', '-n', '32', '::'])
    subprocess.check_call(['syslinux', '--install', f.name])
    subprocess.check_call(['mcopy', '-i', f.name,
            '/usr/share/ipxe/ipxe.lkrn', '::ipxe.lkrn'])
    mcopy = subprocess.Popen(['mcopy', '-i', f.name, '-', '::syslinux.cfg'],
            stdin=subprocess.PIPE)
    mcopy.communicate("""\
DEFAULT ipxe
LABEL ipxe
KERNEL ipxe.lkrn
APPEND dhcp && chain %s
""" % absolute_url('/systems/by-uuid/${uuid}/ipxe-script', scheme='http', labdomain=True))
    if mcopy.returncode != 0:
        raise RuntimeError('mcopy syslinux.cfg failed with return code %s'
                % mcopy.returncode)
    return f
コード例 #54
0
ファイル: ipxe_image.py プロジェクト: beaker-project/beaker
def generate_image():
    f = tempfile.NamedTemporaryFile(suffix=".beaker-ipxe-image")
    log.debug("Generating image in %s", f.name)
    subprocess.check_call(["mformat", "-i", f.name, "-C", "-t", "4", "-h", "64", "-n", "32", "::"])
    subprocess.check_call(["syslinux", "--install", f.name])
    subprocess.check_call(["mcopy", "-i", f.name, "/usr/share/ipxe/ipxe.lkrn", "::ipxe.lkrn"])
    mcopy = subprocess.Popen(["mcopy", "-i", f.name, "-", "::syslinux.cfg"], stdin=subprocess.PIPE)
    mcopy.communicate(
        """\
DEFAULT ipxe
LABEL ipxe
KERNEL ipxe.lkrn
APPEND dhcp && chain %s
"""
        % absolute_url("/systems/by-uuid/${uuid}/ipxe-script", scheme="http", labdomain=True)
    )
    if mcopy.returncode != 0:
        raise RuntimeError("mcopy syslinux.cfg failed with return code %s" % mcopy.returncode)
    return f
コード例 #55
0
ファイル: ipxe_image.py プロジェクト: ShaolongHu/beaker
def generate_image():
    f = tempfile.NamedTemporaryFile(suffix='.beaker-ipxe-image')
    log.debug('Generating image in %s', f.name)
    f.truncate(4 * 1024 * 1024) # 4MB
    subprocess.check_call(['mkdosfs', f.name], stdout=open('/dev/null', 'a'))
    subprocess.check_call(['syslinux', '--install', f.name])
    subprocess.check_call(['mcopy', '-i', f.name,
            '/usr/share/ipxe/ipxe.lkrn', '::ipxe.lkrn'])
    mcopy = subprocess.Popen(['mcopy', '-i', f.name, '-', '::syslinux.cfg'],
            stdin=subprocess.PIPE)
    mcopy.communicate("""\
DEFAULT ipxe
LABEL ipxe
KERNEL ipxe.lkrn
APPEND dhcp && chain %s
""" % absolute_url('/systems/by-uuid/${uuid}/ipxe-script', scheme='http', labdomain=True))
    if mcopy.returncode != 0:
        raise RuntimeError('mcopy syslinux.cfg failed with return code %s'
                % mcopy.returncode)
    return f
コード例 #56
0
ファイル: user.py プロジェクト: walbon/beaker
def create_user():
    """
    Creates a new user account in Beaker.
    """
    data = read_json_request(request)
    with convert_internal_errors():
        new_user_name = data.get('user_name', '').strip()
        existing_user = User.by_user_name(new_user_name)
        if existing_user is not None:
            raise Conflict409('User %s already exists' % new_user_name)
        new_display_name = data.get('display_name', '').strip()
        new_email_address = data.get('email_address', '').strip()
        user = User(user_name=new_user_name,
                    display_name=new_display_name,
                    email_address=new_email_address)
        session.add(user)
        session.flush()  # to populate id
    response = jsonify(user_full_json(user))
    response.status_code = 201
    response.headers.add('Location', absolute_url(user.href))
    return response
コード例 #57
0
ファイル: user.py プロジェクト: beaker-project/beaker
def create_user():
    """
    Creates a new user account in Beaker.
    """
    data = read_json_request(request)
    with convert_internal_errors():
        new_user_name = data.get('user_name', '').strip()
        existing_user = User.by_user_name(new_user_name)
        if existing_user is not None:
            raise Conflict409('User %s already exists' % new_user_name)
        new_display_name = data.get('display_name', '').strip()
        new_email_address = data.get('email_address', '').strip()
        user = User(user_name=new_user_name,
                    display_name=new_display_name,
                    email_address=new_email_address)
        session.add(user)
        session.flush() # to populate id
    response = jsonify(user_full_json(user))
    response.status_code = 201
    response.headers.add('Location', absolute_url(user.href))
    return response
コード例 #58
0
ファイル: test_mail.py プロジェクト: walbon/beaker
    def _create_open_reservation(self):
        system = data_setup.create_system()
        data_setup.create_manual_reservation(system,
                                             start=datetime.utcnow() - timedelta(days=self.reservation_length),
                                             user=self.user)
        recipe = data_setup.create_recipe()
        recipe.systems[:] = [system]
        job = data_setup.create_job_for_recipes([recipe])
        data_setup.mark_job_queued(job)
        job.recipesets[0].queue_time = datetime.utcnow() - timedelta(hours=self.waiting_recipe_age)
        email_content = u"""
The following systems have been allocated to you in %s for more than %s days and have other
recipes queued for longer than %s hours. Please return them if you are no longer using them.

Duration                 Waiting                  FQDN
%s                   %s                 %s
"""    % (absolute_url('/'),
          self.reservation_length,
          self.waiting_recipe_age,
          "%s days" % (datetime.utcnow() - system.reservations[0].start_time).days,
          "1 recipe",
          system.fqdn)
        return email_content
コード例 #59
0
def main(*args):
    parser = get_parser()
    (options, args) = parser.parse_args(*args)
    load_config_or_exit(options.configfile)
    log_to_stream(sys.stderr)
    interface.start(config)
    reservation_expiry = options.reservation_expiry
    reservation_length = options.reservation_length
    waiting_recipe_age = options.waiting_recipe_age
    delayed_job_age = options.delayed_job_age
    testing = options.testing

    if testing:
        print 'Dry run only, nothing will be sent\n'

    for user in User.query:
        beaker_usage = BeakerUsage(user, reservation_expiry,
                                   reservation_length, waiting_recipe_age,
                                   delayed_job_age)
        expiring_reservations = beaker_usage.expiring_reservations()
        open_in_demand_systems = beaker_usage.open_in_demand_systems()
        delayed_jobs = beaker_usage.delayed_jobs()
        if (expiring_reservations or open_in_demand_systems or delayed_jobs):
            data = {
                'user_name': user.user_name,
                'current_date': datetime.utcnow().strftime("%Y-%m-%d"),
                'beaker_fqdn': absolute_url('/'),
                'reservation_expiry': reservation_expiry,
                'reservation_length': reservation_length,
                'waiting_recipe_age': waiting_recipe_age,
                'delayed_job_age': delayed_job_age,
                'expiring_reservations': expiring_reservations,
                'open_reservations': open_in_demand_systems,
                'delayed_jobs': delayed_jobs
            }
            mail.send_usage_reminder(user, data, testing)
    return