Пример #1
0
def get_selected(
    resources_ids: Optional[List[ResourceId]] = None,
    start: Optional[str] = None,
    end: Optional[str] = None
) -> Tuple[Union[List[Any], Content], HttpStatusCode]:
    # TODO This may need a decent refactor - give more freedom
    # All args are required at once, otherwise return 400
    all_not_none = resources_ids and start and end
    if all_not_none:
        try:
            start_as_datetime = DateUtils.parse_string(start)
            ends_as_datetime = DateUtils.parse_string(end)
            matches = list(
                Reservation.filter_by_uuids_and_time_range(
                    resources_ids, start_as_datetime, ends_as_datetime))
            matches = [match.as_dict() for match in matches]
        except (ValueError, AssertionError) as reason:
            content = {'msg': '{}. {}'.format(GENERAL['bad_request'], reason)}
            status = 400
        except Exception as e:
            content = {'msg': GENERAL['internal_error'] + str(e)}
            status = 500
        else:
            content = matches  # type: ignore
            status = 200
    else:
        content = {'msg': GENERAL['bad_request']}
        status = 400
    return content, status
Пример #2
0
def test_create_job(tables, client, new_user):
    new_user.save()
    job_name = 'TestJob'
    data = {
        'name':
        job_name,
        'description':
        'testDescription',
        'userId':
        1,
        'startAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() +
                                                   timedelta(hours=5)),
        'stopAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() +
                                                   timedelta(hours=10))
    }

    resp = client.post(ENDPOINT, headers=HEADERS, data=json.dumps(data))
    resp_json = json.loads(resp.data.decode('utf-8'))

    assert resp.status_code == HTTPStatus.CREATED
    assert resp_json['job']['id'] is not None
    assert resp_json['job']['name'] == job_name
    assert Job.get(int(resp_json['job']['id'])) is not None
Пример #3
0
def business_create(task: Dict[str, Any]) -> Tuple[Content, HttpStatusCode]:
    """Creates new Task db record.
    Fields which require to be of datetime type are explicitly converted here.
    """
    try:
        new_task = Task(
            user_id=task['userId'],
            hostname=task['hostname'],
            command=task['command'],
            # TODO Adjust API spec, optional fields
            spawn_at=DateUtils.try_parse_string(task.get('spawnAt')),
            terminate_at=DateUtils.try_parse_string(task.get('terminateAt')))
        # assert all(task.values()), 'fields cannot be blank or null'
        new_task.save()
    except ValueError:
        # Invalid string format for datetime
        content, status = {'msg': GENERAL['bad_request']}, 422
    except KeyError:
        # At least one of required fields was not present
        content, status = {'msg': GENERAL['bad_request']}, 422
    except AssertionError as e:
        content, status = {
            'msg': TASK['create']['failure']['invalid'].format(reason=e)
        }, 422
    except Exception as e:
        log.critical(e)
        content, status = {'msg': GENERAL['internal_error']}, 500
    else:
        content, status = {
            'msg': TASK['create']['success'],
            'task': new_task.as_dict()
        }, 201
    finally:
        return content, status
Пример #4
0
 def stop_at(self, value):
     if value is not None:
         self._stop_at = DateUtils.try_parse_string(value)
         if self._stop_at is None:
             log.error('Unsupported type (start_at={})'.format(value))
     else:
         self._stop_at = None
Пример #5
0
def create(restriction: Dict[str, Any]) -> Tuple[Content, HttpStatusCode]:
    try:
        new_restriction = Restriction(name=restriction.get('name'),
                                      starts_at=restriction['startsAt'],
                                      is_global=restriction['isGlobal'],
                                      ends_at=DateUtils.try_parse_string(
                                          restriction.get('endsAt')))
        new_restriction.save()
    except AssertionError as e:
        content = {
            'msg': RESTRICTION['create']['failure']['invalid'].format(reason=e)
        }
        status = HTTPStatus.UNPROCESSABLE_ENTITY.value
    except Exception as e:
        content = {'msg': GENERAL['internal_error'] + str(e)}
        status = HTTPStatus.INTERNAL_SERVER_ERROR.value
    else:
        content = {
            'msg':
            RESTRICTION['create']['success'],
            'restriction':
            new_restriction.as_dict(include_groups=True,
                                    include_users=True,
                                    include_resources=True)
        }
        status = HTTPStatus.CREATED.value
    finally:
        return content, status
Пример #6
0
def test_update_not_owned_job(tables, client, new_admin_job):
    new_admin_job.save()
    data = {
        'name':
        'NewName',
        'description':
        'NewDescription',
        'startAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() +
                                                   timedelta(hours=5)),
        'stopAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() +
                                                   timedelta(hours=10)),
    }
    resp = client.put(ENDPOINT + '/{}'.format(new_admin_job.id),
                      headers=HEADERS,
                      data=json.dumps(data))
    assert resp.status_code == HTTPStatus.FORBIDDEN
Пример #7
0
def test_update_job_to_stop_before_start(tables, client, new_job):
    new_job._status = JobStatus.running
    new_job.save()
    data = {
        'name':
        'NewName',
        'description':
        'NewDescription',
        'startAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() -
                                                   timedelta(hours=5)),
        'stopAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() -
                                                   timedelta(hours=10)),
    }
    resp = client.put(ENDPOINT + '/{}'.format(new_job.id),
                      headers=HEADERS,
                      data=json.dumps(data))
    assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
Пример #8
0
 def start_at(self, value):
     if value is not None:
         self._start_at = DateUtils.try_parse_string(value)
         if self._start_at is None:
             log.error('Unsupported type (start_at={})'.format(value))
         else:
             assert self._start_at > datetime.utcnow(
             ), 'Job start time must be in the future!'
     else:
         self._start_at = None
def test_update_future_reservation_start(tables, client, future_reservation,
                                         permissive_restriction):
    permissive_restriction.save()
    future_reservation.save()

    new_reservation_start = future_reservation.start + timedelta(hours=1)
    resp = client.put(
        ENDPOINT + '/' + str(future_reservation.id),
        headers=HEADERS,
        data=json.dumps({
            'start':
            DateUtils.stringify_datetime_to_api_format(new_reservation_start)
        }))
    resp_json = json.loads(resp.data.decode('utf-8'))

    assert resp.status_code == HTTPStatus.CREATED
    assert resp_json['reservation']['start'] == DateUtils.stringify_datetime(
        new_reservation_start)
    assert Reservation.get(
        future_reservation.id).start == new_reservation_start
Пример #10
0
def test_create_job_in_the_past(tables, client, new_user):
    new_user.save()
    job_name = 'TestJob'
    data = {
        'name':
        job_name,
        'description':
        'testDescription',
        'userId':
        1,
        'startAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() -
                                                   timedelta(hours=5)),
        'stopAt':
        DateUtils.stringify_datetime_to_api_format(datetime.datetime.utcnow() +
                                                   timedelta(hours=10))
    }

    resp = client.post(ENDPOINT, headers=HEADERS, data=json.dumps(data))
    assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
def test_create_reservation_starting_in_the_past(tables, client, new_user,
                                                 permissive_restriction):
    new_user.save()

    # Create a resource and assign it to the restriction
    resource = Resource(id='0123456789012345678901234567890123456789')
    resource.save()

    past_time = datetime.datetime.now() - timedelta(minutes=2)
    end_time = past_time + timedelta(hours=1)

    data = {
        'title': 'Test reservation',
        'description': 'Test reservation',
        'resourceId': '0123456789012345678901234567890123456789',
        'userId': new_user.id,
        'start': DateUtils.stringify_datetime_to_api_format(past_time),
        'end': DateUtils.stringify_datetime_to_api_format(end_time)
    }
    resp = client.post(ENDPOINT, headers=HEADERS, data=json.dumps(data))

    assert resp.status_code == HTTPStatus.FORBIDDEN
def test_create_reservation(tables, client, new_user, permissive_restriction):
    new_user.save()

    # Create a resource and assign it to the restriction
    resource = Resource(id='0123456789012345678901234567890123456789')
    resource.save()

    # Try to create reservation for a period that the user has access to, as specified by the restriction.
    # Should succeed.
    now = datetime.datetime.now()
    data = {
        'title': 'Test reservation',
        'description': 'Test reservation',
        'resourceId': '0123456789012345678901234567890123456789',
        'userId': new_user.id,
        'start': DateUtils.stringify_datetime_to_api_format(now),
        'end':
        DateUtils.stringify_datetime_to_api_format(now + timedelta(hours=1))
    }
    resp = client.post(ENDPOINT, headers=HEADERS, data=json.dumps(data))
    resp_json = json.loads(resp.data.decode('utf-8'))

    assert resp.status_code == HTTPStatus.CREATED
    assert Reservation.get(resp_json['reservation']['id']) is not None
Пример #13
0
def create(reservation: Dict[str, Any]) -> Tuple[Content, HttpStatusCode]:
    try:
        new_reservation = Reservation(title=reservation['title'],
                                      description=reservation['description'],
                                      resource_id=reservation['resourceId'],
                                      user_id=reservation['userId'],
                                      start=reservation['start'],
                                      end=reservation['end'])

        if not is_admin() and not __is_reservation_owner(new_reservation):
            raise ForbiddenException(
                "Cannot reserve resources in another user's name")

        reservation_start = DateUtils.try_parse_string(new_reservation.start)
        request_time_limit = timedelta(minutes=1)
        starts_in_the_future = (reservation_start +
                                request_time_limit) >= datetime.utcnow()
        if not is_admin() and not starts_in_the_future:
            raise ForbiddenException("Cannot reserve resources in the past")

        user = User.get(get_jwt_identity())
        if not ReservationVerifier.is_reservation_allowed(
                user, new_reservation):
            raise ForbiddenException("Reservation not allowed")

        new_reservation.save()
        content = {
            'msg': RESERVATION['create']['success'],
            'reservation': new_reservation.as_dict()
        }
        status = 201
    except ForbiddenException as e:
        content = {
            'msg':
            RESERVATION['create']['failure']['forbidden'].format(reason=e)
        }
        status = 403
    except AssertionError as e:
        content = {
            'msg': RESERVATION['create']['failure']['invalid'].format(reason=e)
        }
        status = 422
    except Exception as e:
        print(e)
        content = {'msg': GENERAL['internal_error'] + str(e)}
        status = 500
    finally:
        return content, status
def test_update_active_reservation_start_forbidden(tables, client,
                                                   active_reservation,
                                                   permissive_restriction):
    permissive_restriction.save()
    active_reservation.save()

    new_reservation_start = active_reservation.start + timedelta(hours=1)
    resp = client.put(
        ENDPOINT + '/' + str(active_reservation.id),
        headers=HEADERS,
        data=json.dumps({
            'start':
            DateUtils.stringify_datetime_to_api_format(new_reservation_start)
        }))

    assert resp.status_code == HTTPStatus.FORBIDDEN
Пример #15
0
def business_update(
        id: TaskId, new_values: Dict[str,
                                     Any]) -> Tuple[Content, HttpStatusCode]:
    """Updates certain fields of a Task db record, see `allowed_fields`."""
    allowed_fields = {'command', 'hostname', 'spawnAt', 'terminateAt'}
    try:
        assert set(new_values.keys()).issubset(
            allowed_fields), 'invalid field is present'
        task = Task.get(id)
        for field_name, new_value in new_values.items():
            if field_name in {'spawnAt', 'terminateAt'}:
                new_value = DateUtils.try_parse_string(new_value)
            field_name = snakecase(field_name)
            # Check that every field matches
            assert (field_name is not None) and hasattr(
                task, field_name), 'task has no {} field'.format(field_name)
            setattr(task, field_name, new_value)
        task.save()
    except NoResultFound:
        content, status = {'msg': TASK['not_found']}, 404
    except ValueError:
        # Invalid string format for datetime
        content, status = {'msg': GENERAL['bad_request']}, 422
    except AssertionError as e:
        content, status = {
            'msg': TASK['update']['failure']['assertions'].format(reason=e)
        }, 422
    except Exception as e:
        log.critical(e)
        content, status = {'msg': GENERAL['internal_error']}, 500
    else:
        content, status = {
            'msg': TASK['update']['success'],
            'task': task.as_dict()
        }, 201
    finally:
        return content, status
Пример #16
0
 def start(self, value):
     self._start = DateUtils.try_parse_string(value)
     if self._start is None:
         log.error('Unsupported type (start={})'.format(value))
Пример #17
0
 def _serialize(self, field):
     if type(field) == datetime.datetime:
         return DateUtils.stringify_datetime(field)
     else:
         return field
Пример #18
0
 def end(self, value):
     self._end = DateUtils.try_parse_string(value)
     if self._end is None:
         log.error('Unsupported type (end={})'.format(value))
Пример #19
0
 def created_at(self, value: str):
     self._created_at = DateUtils.try_parse_string(value)
     if self._created_at is None:
         log.error('Unsupported type (created_at={})'.format(value))
Пример #20
0
 def ends_at(self, value: str):
     self._ends_at = DateUtils.try_parse_string(value)