def test_update_cluster_set_lifespan_forbidden(client, mocker): mocker.patch( 'rhub.api.lab.cluster._user_can_set_lifespan').return_value = False region = _create_test_region() region.lifespan_length = 30 product = _create_test_product() cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=region.id, region=region, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=1, product_params={}, product=product, ) model.Cluster.query.get.return_value = cluster rv = client.patch( f'{API_BASE}/lab/cluster/1', headers={'Authorization': 'Bearer foobar'}, json={ 'lifespan_expiration': '2100-01-01T00:00:00Z', }, ) assert rv.status_code == 403
def test_update_cluster_ro_field(client, cluster_data): region = _create_test_region() product = _create_test_product() cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=region.id, region=region, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=1, product_params={}, product=product, ) model.Cluster.query.get.return_value = cluster rv = client.patch( f'{API_BASE}/lab/cluster/1', headers={'Authorization': 'Bearer foobar'}, json=cluster_data, ) assert rv.status_code == 400
def test_update_cluster_exceeded_reservation(client): region = _create_test_region() region.reservation_expiration_max = 1 product = _create_test_product() cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=region.id, region=region, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=1, product_params={}, product=product, ) model.Cluster.query.get.return_value = cluster new_expiration = datetime.datetime(2100, 1, 1, 0, 0, tzinfo=tzutc()) rv = client.patch( f'{API_BASE}/lab/cluster/1', headers={'Authorization': 'Bearer foobar'}, json={ 'reservation_expiration': new_expiration, }, ) assert rv.status_code == 403 assert rv.json['detail'] == 'Exceeded maximal reservation time.'
def test_create_cluster_hosts(client, db_session_mock): model.Cluster.query.get.return_value = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=1, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, ) hosts_data = [ { 'fqdn': 'host0.example.com', 'ipaddr': ['1.2.3.4'], 'num_vcpus': 2, 'ram_mb': 2048, 'num_volumes': 3, 'volumes_gb': 30, }, { 'fqdn': 'host1.example.com', 'ipaddr': ['1:2::3:4'], 'num_vcpus': 2, 'ram_mb': 2048, 'num_volumes': 3, 'volumes_gb': 30, }, ] rv = client.post( f'{API_BASE}/lab/cluster/1/hosts', headers={'Authorization': 'Bearer foobar'}, json=hosts_data, ) assert rv.status_code == 200 db_session_mock.add_all.assert_called() db_session_mock.commit.assert_called() hosts = db_session_mock.add_all.call_args.args[0] for host_data, host_row in zip(hosts_data, hosts): for k, v in host_data.items(): assert getattr(host_row, k) == v
def test_update_cluster_reservation(client, keycloak_mock, db_session_mock): user_id = '00000000-0000-0000-0000-000000000000' keycloak_mock.user_get.return_value = { 'id': user_id, 'username': '******' } region = _create_test_region() product = _create_test_product() old_expiration = datetime.datetime(2100, 1, 1, 0, 0, tzinfo=tzutc()) new_expiration = datetime.datetime(2100, 1, 2, 0, 0, tzinfo=tzutc()) cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=region.id, region=region, reservation_expiration=old_expiration, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=1, product_params={}, product=product, ) model.Cluster.query.get.return_value = cluster rv = client.patch( f'{API_BASE}/lab/cluster/1', headers={'Authorization': 'Bearer foobar'}, json={ 'reservation_expiration': new_expiration, }, ) assert rv.status_code == 200 assert cluster.reservation_expiration == new_expiration event = db_session_mock.add.call_args_list[0].args[0] assert event.type == model.ClusterEventType.RESERVATION_CHANGE assert event.old_value == old_expiration assert event.new_value == new_expiration
def test_update_cluster(client, keycloak_mock, db_session_mock): region = _create_test_region() product = _create_test_product() user_id = '00000000-0000-0000-0000-000000000000' keycloak_mock.user_get.return_value = { 'id': user_id, 'username': '******' } keycloak_mock.group_get.return_value = {'id': None, 'name': 'None'} cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=region.id, region=region, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=1, product_params={}, product=product, ) model.Cluster.query.get.return_value = cluster rv = client.patch( f'{API_BASE}/lab/cluster/1', headers={'Authorization': 'Bearer foobar'}, json={ 'description': 'test change', 'group_id': '00000001-0002-0003-0004-000000000000', }, ) assert rv.status_code == 200 db_session_mock.commit.assert_called() assert cluster.description == 'test change' assert cluster.group_id == '00000001-0002-0003-0004-000000000000'
def test_delete_cluster_hosts(client, db_session_mock): hosts = [ model.ClusterHost( id=1, cluster_id=1, fqdn='host0.example.com', ipaddr=['1.2.3.4'], ), model.ClusterHost( id=2, cluster_id=1, fqdn='host1.example.com', ipaddr=['1:2::3:4'], ), ] cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=1, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, hosts=hosts, ) model.Cluster.query.get.return_value = cluster rv = client.delete( f'{API_BASE}/lab/cluster/1/hosts', headers={'Authorization': 'Bearer foobar'}, ) assert rv.status_code == 204 for host in hosts: db_session_mock.delete.assert_any_call(host) db_session_mock.commit.assert_called()
def test_get_cluster_events(client): events = [ model.ClusterTowerJobEvent( id=1, date=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), user_id='00000000-0000-0000-0000-000000000000', cluster_id=1, tower_id=1, tower=tower_model.Server(id=1), tower_job_id=1, status=model.ClusterStatus.POST_PROVISIONING, ), model.ClusterReservationChangeEvent( id=2, date=datetime.datetime(2021, 1, 1, 2, 0, 0, tzinfo=tzutc()), user_id='00000000-0000-0000-0000-000000000000', cluster_id=1, old_value=None, new_value=datetime.datetime(2021, 2, 1, 0, 0, 0, tzinfo=tzutc()), ), ] cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=1, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, events=events, ) model.Cluster.query.get.return_value = cluster rv = client.get( f'{API_BASE}/lab/cluster/1/events', headers={'Authorization': 'Bearer foobar'}, ) assert rv.status_code == 200 model.Cluster.query.get.assert_called_with(1) assert rv.json == [ { 'id': 1, 'type': model.ClusterEventType.TOWER_JOB.value, 'cluster_id': 1, 'date': '2021-01-01T01:00:00+00:00', 'user_id': '00000000-0000-0000-0000-000000000000', 'user_name': 'test-user', 'tower_id': 1, 'tower_job_id': 1, 'status': model.ClusterStatus.POST_PROVISIONING.value, '_href': ANY, }, { 'id': 2, 'type': model.ClusterEventType.RESERVATION_CHANGE.value, 'cluster_id': 1, 'date': '2021-01-01T02:00:00+00:00', 'user_id': '00000000-0000-0000-0000-000000000000', 'user_name': 'test-user', 'old_value': None, 'new_value': '2021-02-01T00:00:00+00:00', '_href': ANY, }, ]
def test_delete_cluster(client, db_session_mock, keycloak_mock, mocker): region = _create_test_region() product = _create_test_product() cluster = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=region.id, region=region, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=product.id, product_params={}, product=product, ) model.Cluster.query.get.return_value = cluster keycloak_mock.user_get.return_value = {'username': '******'} mocker.patch.object(cluster.region, 'tower') mocker.patch.object(cluster.region.tower, 'create_tower_client') cluster.region.tower.create_tower_client.return_value = (tower_client_mock := mocker.Mock( name='foo')) tower_client_mock.template_get.return_value = { 'id': 123, 'name': 'dummy-delete' } tower_client_mock.template_launch.return_value = {'id': 321} rv = client.delete( f'{API_BASE}/lab/cluster/1', headers={'Authorization': 'Bearer foobar'}, ) assert rv.status_code == 204 region.tower.create_tower_client.assert_called() tower_client_mock.template_get.assert_called_with( template_name='dummy-delete') tower_client_mock.template_launch.assert_called_with( 123, { 'extra_vars': { 'rhub_cluster_id': 1, 'rhub_cluster_name': 'testcluster', 'rhub_product_id': product.id, 'rhub_product_name': product.name, 'rhub_region_id': region.id, 'rhub_region_name': region.name, 'rhub_user_id': cluster.user_id, 'rhub_user_name': 'test-user', }, }) db_session_mock.delete.assert_called_with(cluster) db_session_mock.commit.assert_called()
def test_list_clusters(client, keycloak_mock, mocker): user_id = '00000000-0000-0000-0000-000000000000' sample_region = _create_test_region() sample_product = _create_test_product() keycloak_mock.user_get.return_value = { 'id': user_id, 'username': '******' } model.Cluster.query.limit.return_value.offset.return_value = [ model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=1, region=sample_region, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=1, product_params={}, product=sample_product, ), ] mocker.patch.object(model.Cluster, 'hosts', []) mocker.patch.object(model.Cluster, 'quota', None) model.Cluster.query.count.return_value = 1 rv = client.get( f'{API_BASE}/lab/cluster', headers={'Authorization': 'Bearer foobar'}, ) keycloak_mock.user_get.assert_called_with(user_id) assert rv.status_code == 200 assert rv.json == { 'data': [ { 'id': 1, 'name': 'testcluster', 'description': 'test cluster', 'user_id': '00000000-0000-0000-0000-000000000000', 'group_id': None, 'created': '2021-01-01T01:00:00+00:00', 'region_id': 1, 'reservation_expiration': None, 'lifespan_expiration': None, 'status': model.ClusterStatus.ACTIVE.value, 'region_name': 'test', 'user_name': 'test-user', 'group_name': None, 'hosts': [], 'quota': None, 'quota_usage': None, 'product_id': 1, 'product_name': 'dummy', 'product_params': {}, 'shared': False, '_href': ANY, }, ], 'total': 1, }
def test_get_cluster(client, keycloak_mock, mocker): user_id = '00000000-0000-0000-0000-000000000000' sample_region = _create_test_region() sample_product = _create_test_product() keycloak_mock.user_get.return_value = { 'id': user_id, 'username': '******' } model.Cluster.query.get.return_value = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=1, region=sample_region, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, product_id=1, product_params={}, product=sample_product, ) mocker.patch.object(model.Cluster, 'hosts', [ model.ClusterHost( id=1, cluster_id=1, fqdn='test0.localhost', ipaddr=['127.0.0.1', '::1'], num_vcpus=2, ram_mb=4096, num_volumes=1, volumes_gb=20, ), model.ClusterHost( id=2, cluster_id=1, fqdn='test1.localhost', ipaddr=['127.0.0.1', '::1'], num_vcpus=2, ram_mb=4096, num_volumes=1, volumes_gb=20, ), ]) mocker.patch.object( model.Cluster, 'quota', model.Quota( id=1, num_vcpus=20, ram_mb=20000, num_volumes=2, volumes_gb=200, )) rv = client.get( f'{API_BASE}/lab/cluster/1', headers={'Authorization': 'Bearer foobar'}, ) assert rv.status_code == 200 model.Cluster.query.get.assert_called_with(1) keycloak_mock.user_get.assert_called_with(user_id) assert rv.json == { 'id': 1, 'name': 'testcluster', 'description': 'test cluster', 'user_id': '00000000-0000-0000-0000-000000000000', 'group_id': None, 'created': '2021-01-01T01:00:00+00:00', 'region_id': 1, 'reservation_expiration': None, 'lifespan_expiration': None, 'status': model.ClusterStatus.ACTIVE.value, 'region_name': 'test', 'user_name': 'test-user', 'group_name': None, 'hosts': [{ 'id': 1, 'cluster_id': 1, 'fqdn': 'test0.localhost', 'ipaddr': ['127.0.0.1', '::1'], 'num_vcpus': 2, 'ram_mb': 4096, 'num_volumes': 1, 'volumes_gb': 20, }, { 'id': 2, 'cluster_id': 1, 'fqdn': 'test1.localhost', 'ipaddr': ['127.0.0.1', '::1'], 'num_vcpus': 2, 'ram_mb': 4096, 'num_volumes': 1, 'volumes_gb': 20, }], 'quota': { 'num_vcpus': 20, 'ram_mb': 20000, 'num_volumes': 2, 'volumes_gb': 200, }, 'quota_usage': { 'num_vcpus': 4, 'ram_mb': 8192, 'num_volumes': 2, 'volumes_gb': 40, }, 'product_id': 1, 'product_name': 'dummy', 'product_params': {}, 'shared': False, '_href': ANY, }
def test_get_cluster_hosts(client): model.Cluster.query.get.return_value = model.Cluster( id=1, name='testcluster', description='test cluster', user_id='00000000-0000-0000-0000-000000000000', group_id=None, created=datetime.datetime(2021, 1, 1, 1, 0, 0, tzinfo=tzutc()), region_id=1, reservation_expiration=None, lifespan_expiration=None, status=model.ClusterStatus.ACTIVE, hosts=[ model.ClusterHost( id=1, cluster_id=1, fqdn='host0.example.com', ipaddr=['1.2.3.4'], num_vcpus=2, ram_mb=2048, num_volumes=3, volumes_gb=30, ), model.ClusterHost( id=2, cluster_id=1, fqdn='host1.example.com', ipaddr=['1:2::3:4'], num_vcpus=2, ram_mb=2048, num_volumes=3, volumes_gb=30, ), ], ) rv = client.get( f'{API_BASE}/lab/cluster/1/hosts', headers={'Authorization': 'Bearer foobar'}, ) assert rv.status_code == 200 model.Cluster.query.get.assert_called_with(1) assert rv.json == [ { 'id': 1, 'cluster_id': 1, 'fqdn': 'host0.example.com', 'ipaddr': ['1.2.3.4'], 'num_vcpus': 2, 'ram_mb': 2048, 'num_volumes': 3, 'volumes_gb': 30, '_href': ANY, }, { 'id': 2, 'cluster_id': 1, 'fqdn': 'host1.example.com', 'ipaddr': ['1:2::3:4'], 'num_vcpus': 2, 'ram_mb': 2048, 'num_volumes': 3, 'volumes_gb': 30, '_href': ANY, }, ]