'Creates a job by taking some information (the listed args)
and filling in the rest of the necessary information.
:param owner: the username of the job owner. set the attribute
:attr:`owner`
:type owner: string
:param options: a dictionary with parameters to be passed to to the
class method :meth:`add_object <Job.add_object>`
:type options: dict
:param hosts: a list of :class:`hosts <Host>` that will be used to
check if the user can indeed send a job to them (by means
of :meth:`AclGroup.check_for_acl_violation_hosts`
:type hosts: list of :class:`Host`'

@classmethod
def create(cls, owner, options, hosts):

    AclGroup.check_for_acl_violation_hosts(hosts)
    control_file = options.get('control_file')
    parameterized_job = options.get('parameterized_job')
    cls.check_parameterized_job(control_file=control_file, parameterized_job=parameterized_job)
    user = User.current_user()
    if (options.get('reboot_before') is None):
        options['reboot_before'] = user.get_reboot_before_display()
    if (options.get('reboot_after') is None):
        options['reboot_after'] = user.get_reboot_after_display()
    drone_set = DroneSet.resolve_name(options.get('drone_set'))
    job = cls.add_object(owner=owner, name=options['name'], priority=options['priority'], control_file=control_file, control_type=options['control_type'], synch_count=options.get('synch_count'), timeout=options.get('timeout'), max_runtime_hrs=options.get('max_runtime_hrs'), run_verify=options.get('run_verify'), email_list=options.get('email_list'), reboot_before=options.get('reboot_before'), reboot_after=options.get('reboot_after'), parse_failed_repair=options.get('parse_failed_repair'), created_on=datetime.now(), drone_set=drone_set, parameterized_job=parameterized_job, reserve_hosts=options.get('reserve_hosts'))
    job.dependency_labels = options['dependencies']
    if options.get('keyvals'):
        for (key, value) in options['keyvals'].iteritems():
            JobKeyval.objects.create(job=job, key=key, value=value)
    return job
