예제 #1
0
 async def update(cls, access_key: str,
                  is_active: bool = None,
                  is_admin: bool = None,
                  resource_policy: str = None,
                  rate_limit: int = None) -> dict:
     """
     Creates a new keypair with the given options.
     You need an admin privilege for this operation.
     """
     q = 'mutation($access_key: String!, $input: ModifyKeyPairInput!) {' + \
         '  modify_keypair(access_key: $access_key, props: $input) {' \
         '    ok msg' \
         '  }' \
         '}'
     variables = {
         'access_key': access_key,
         'input': {
             'is_active': is_active,
             'is_admin': is_admin,
             'resource_policy': resource_policy,
             'rate_limit': rate_limit,
         },
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': q,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['modify_keypair']
예제 #2
0
    async def list(cls, domain_name: str,
                   fields: Iterable[str] = None) -> Sequence[dict]:
        '''
        Fetches the list of groups.

        :param domain_name: Name of domain to list groups.
        :param fields: Additional per-group query fields to fetch.
        '''
        if fields is None:
            fields = ('id', 'name', 'description', 'is_active',
                      'created_at', 'domain_name',
                      'total_resource_slots', 'allowed_vfolder_hosts',
                      'integration_id')
        query = textwrap.dedent('''\
            query($domain_name: String) {
                groups(domain_name: $domain_name) {$fields}
            }
        ''')
        query = query.replace('$fields', ' '.join(fields))
        variables = {'domain_name': domain_name}
        rqst = Request(cls.session, 'POST', '/admin/graphql')
        rqst.set_json({
            'query': query,
            'variables': variables,
        })
        async with rqst.fetch() as resp:
            data = await resp.json()
            return data['groups']
예제 #3
0
    async def detail(cls, gid: str, fields: Iterable[str] = None) -> Sequence[dict]:
        '''
        Fetch information of a group with group ID.

        :param gid: ID of the group to fetch.
        :param fields: Additional per-group query fields to fetch.
        '''
        if fields is None:
            fields = ('id', 'name', 'description', 'is_active', 'created_at', 'domain_name',
                      'total_resource_slots', 'allowed_vfolder_hosts', 'integration_id')
        query = textwrap.dedent('''\
            query($gid: String!) {
                group(id: $gid) {$fields}
            }
        ''')
        query = query.replace('$fields', ' '.join(fields))
        variables = {'gid': gid}
        rqst = Request(cls.session, 'POST', '/admin/graphql')
        rqst.set_json({
            'query': query,
            'variables': variables,
        })
        async with rqst.fetch() as resp:
            data = await resp.json()
            return data['group']
예제 #4
0
 async def remove_users(cls, gid: str, user_uuids: Iterable[str],
                        fields: Iterable[str] = None) -> dict:
     '''
     Remove users from a group.
     You need an admin privilege for this operation.
     '''
     query = textwrap.dedent('''\
         mutation($gid: String!, $input: ModifyGroupInput!) {
             modify_group(gid: $gid, props: $input) {
                 ok msg
             }
         }
     ''')
     variables = {
         'gid': gid,
         'input': {
             'user_update_mode': 'remove',
             'user_uuids': user_uuids,
         },
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': query,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['modify_group']
예제 #5
0
    async def list(cls,
                   operation: bool = False,
                   fields: Iterable[str] = None) -> Sequence[dict]:
        '''
        Fetches the list of registered images in this cluster.
        '''

        if fields is None:
            fields = (
                'name',
                'tag',
                'hash',
            )
        q = 'query($is_operation: Boolean) {' \
            '  images(is_operation: $is_operation) {' \
            '    $fields' \
            '  }' \
            '}'
        q = q.replace('$fields', ' '.join(fields))
        variables = {
            'is_operation': operation,
        }
        rqst = Request(cls.session, 'POST', '/admin/graphql')
        rqst.set_json({
            'query': q,
            'variables': variables,
        })
        async with rqst.fetch() as resp:
            data = await resp.json()
            return data['images']
예제 #6
0
 async def update(cls, gid: str, name: str = None, description: str = None,
                  is_active: bool = None, total_resource_slots: str = None,
                  allowed_vfolder_hosts: Iterable[str] = None,
                  integration_id: str = None,
                  fields: Iterable[str] = None) -> dict:
     '''
     Update existing group.
     You need an admin privilege for this operation.
     '''
     query = textwrap.dedent('''\
         mutation($gid: String!, $input: ModifyGroupInput!) {
             modify_group(gid: $gid, props: $input) {
                 ok msg
             }
         }
     ''')
     variables = {
         'gid': gid,
         'input': {
             'name': name,
             'description': description,
             'is_active': is_active,
             'total_resource_slots': total_resource_slots,
             'allowed_vfolder_hosts': allowed_vfolder_hosts,
             'integration_id': integration_id,
         },
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': query,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['modify_group']
예제 #7
0
    async def info(self, fields: Iterable[str] = None) -> dict:
        '''
        Returns the keypair's information such as resource limits.

        :param fields: Additional per-agent query fields to fetch.

        .. versionadded:: 18.12
        '''
        if fields is None:
            fields = (
                'access_key', 'secret_key',
                'is_active', 'is_admin',
            )
        q = 'query {' \
            '  keypair {' \
            '    $fields' \
            '  }' \
            '}'
        q = q.replace('$fields', ' '.join(fields))
        rqst = Request(self.session, 'POST', '/admin/graphql')
        rqst.set_json({
            'query': q,
        })
        async with rqst.fetch() as resp:
            data = await resp.json()
            return data['keypair']
예제 #8
0
 async def deactivate(cls, access_key: str) -> dict:
     '''
     Deactivates this keypair.
     Deactivated keypairs cannot make any API requests
     unless activated again by an administrator.
     You need an admin privilege for this operation.
     '''
     q = 'mutation($access_key: String!, $input: ModifyKeyPairInput!) {' + \
         '  modify_keypair(access_key: $access_key, props: $input) {' \
         '    ok msg' \
         '  }' \
         '}'
     variables = {
         'access_key': access_key,
         'input': {
             'is_active': False,
             'is_admin': None,
             'resource_policy': None,
             'rate_limit': None,
         },
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': q,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['modify_keypair']
예제 #9
0
 def test_auth(self):
     random_msg = uuid.uuid4().hex
     with Session() as sess:
         request = Request(sess, 'GET', '/auth')
         request.set_json({
             'echo': random_msg,
         })
         with request.fetch() as resp:
             assert resp.status == 200
             data = resp.json()
             assert data['authorized'] == 'yes'
             assert data['echo'] == random_msg
예제 #10
0
def test_auth():
    random_msg = uuid.uuid4().hex
    with Session() as sess:
        request = Request('GET', '/auth')
        request.set_json({
            'echo': random_msg,
        })
        with request.fetch() as resp:
            assert resp.status == 200
            data = resp.json()
            assert data['authorized'] == 'yes'
            assert data['echo'] == random_msg
예제 #11
0
def test_auth_missing_signature(monkeypatch):
    random_msg = uuid.uuid4().hex
    with Session() as sess:
        rqst = Request('GET', '/auth')
        rqst.set_json({'echo': random_msg})
        # let it bypass actual signing
        from ai.backend.client import request
        noop_sign = lambda *args, **kwargs: ({}, None)
        monkeypatch.setattr(request, 'generate_signature', noop_sign)
        with pytest.raises(BackendAPIError) as e:
            with rqst.fetch():
                pass
        assert e.value.status == 401
예제 #12
0
 def test_auth_missing_signature(self, monkeypatch):
     random_msg = uuid.uuid4().hex
     with Session() as sess:
         rqst = Request(sess, 'GET', '/auth')
         rqst.set_json({'echo': random_msg})
         # let it bypass actual signing
         from ai.backend.client import request
         noop_sign = lambda *args, **kwargs: ({}, None)
         monkeypatch.setattr(request, 'generate_signature', noop_sign)
         with pytest.raises(BackendAPIError) as e:
             with rqst.fetch():
                 pass
         assert e.value.status == 401
예제 #13
0
 async def dealias_image(cls, alias: str) -> dict:
     q = 'mutation($alias: String!) {' \
         '  dealias_image(alias: $alias) {' \
         '   ok msg' \
         '  }' \
         '}'
     variables = {
         'alias': alias,
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': q,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['dealias_image']
예제 #14
0
 async def rescan_images(cls, registry: str):
     q = 'mutation($registry: String) {' \
         '  rescan_images(registry:$registry) {' \
         '   ok msg' \
         '  }' \
         '}'
     variables = {
         'registry': registry,
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': q,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['rescan_images']
예제 #15
0
 async def delete(cls, gid: str):
     '''
     Deletes an existing group.
     '''
     query = textwrap.dedent('''\
         mutation($gid: String!) {
             delete_group(gid: $gid) {
                 ok msg
             }
         }
     ''')
     variables = {'gid': gid}
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': query,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['delete_group']
예제 #16
0
 async def delete(cls, access_key: str):
     """
     Deletes an existing keypair with given ACCESSKEY.
     """
     q = 'mutation($access_key: String!) {' \
         '  delete_keypair(access_key: $access_key) {' \
         '    ok msg' \
         '  }' \
         '}'
     variables = {
         'access_key': access_key,
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': q,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['delete_keypair']
예제 #17
0
 async def list(cls, user_id: Union[int, str] = None,
                is_active: bool = None,
                fields: Iterable[str] = None) -> Sequence[dict]:
     '''
     Lists the keypairs.
     You need an admin privilege for this operation.
     '''
     if fields is None:
         fields = (
             'access_key', 'secret_key',
             'is_active', 'is_admin',
         )
     if user_id is None:
         q = 'query($is_active: Boolean) {' \
             '  keypairs(is_active: $is_active) {' \
             '    $fields' \
             '  }' \
             '}'
     else:
         uid_type = 'Int!' if isinstance(user_id, int) else 'String!'
         q = 'query($email: {0}, $is_active: Boolean) {{'.format(uid_type) + \
             '  keypairs(email: $email, is_active: $is_active) {' \
             '    $fields' \
             '  }' \
             '}'
     q = q.replace('$fields', ' '.join(fields))
     variables = {
         'is_active': is_active,
     }
     if user_id is not None:
         variables['email'] = user_id
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': q,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['keypairs']
예제 #18
0
 async def create(cls, domain_name: str, name: str, description: str = '',
                  is_active: bool = True, total_resource_slots: str = None,
                  allowed_vfolder_hosts: Iterable[str] = None,
                  integration_id: str = None,
                  fields: Iterable[str] = None) -> dict:
     '''
     Creates a new group with the given options.
     You need an admin privilege for this operation.
     '''
     if fields is None:
         fields = ('id', 'domain_name', 'name',)
     query = textwrap.dedent('''\
         mutation($name: String!, $input: GroupInput!) {
             create_group(name: $name, props: $input) {
                 ok msg group {$fields}
             }
         }
     ''')
     query = query.replace('$fields', ' '.join(fields))
     variables = {
         'name': name,
         'input': {
             'description': description,
             'is_active': is_active,
             'domain_name': domain_name,
             'total_resource_slots': total_resource_slots,
             'allowed_vfolder_hosts': allowed_vfolder_hosts,
             'integration_id': integration_id,
         },
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': query,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['create_group']
예제 #19
0
async def test_upload_jwt_generation(tmp_path):
    with aioresponses() as m:

        async with AsyncSession() as session:
            mock_file = tmp_path / 'example.bin'
            mock_file.write_bytes(secrets.token_bytes(32))

            vfolder_name = 'fake-vfolder-name'

            file_size = '1024'
            payload = {
                'token':
                'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. \
            eyJwYXRoIjoiaHR0cDoxMjcuMC4wLjEvZm9sZGVycy9mYWtlLXZmb2xkZXItbmFtZS9yZXF1ZXN0LXVwbG9hZCIsInNpemUiOjEwMjR9.\
            5IXk0xdrr6aPzVjud4cdfcXWch7Bq-m7SlFhnUv8XL8'
            }

            m.post(
                build_url(session.config,
                          '/folders/{}/request-upload'.format(vfolder_name)),
                payload=payload,
                status=200)

            rqst = Request('POST',
                           '/folders/{}/request-upload'.format(vfolder_name))
            rqst.set_json({
                'path': "{}".format(str(Path(mock_file))),
                'size': str(file_size),
            })

            async with rqst.fetch() as resp:
                res = await resp.json()
                assert isinstance(resp, Response)
                assert resp.status == 200
                assert resp.content_type == 'application/json'
                assert res == payload
                assert 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9' in res['token']
예제 #20
0
 async def create(cls, user_id: Union[int, str],
                  is_active: bool = True,
                  is_admin: bool = False,
                  resource_policy: str = None,
                  rate_limit: int = None,
                  fields: Iterable[str] = None) -> dict:
     '''
     Creates a new keypair with the given options.
     You need an admin privilege for this operation.
     '''
     if fields is None:
         fields = ('access_key', 'secret_key')
     uid_type = 'Int!' if isinstance(user_id, int) else 'String!'
     q = 'mutation($user_id: {0}, $input: KeyPairInput!) {{'.format(uid_type) + \
         '  create_keypair(user_id: $user_id, props: $input) {' \
         '    ok msg keypair { $fields }' \
         '  }' \
         '}'
     q = q.replace('$fields', ' '.join(fields))
     variables = {
         'user_id': user_id,
         'input': {
             'is_active': is_active,
             'is_admin': is_admin,
             'resource_policy': resource_policy,
             'rate_limit': rate_limit,
         },
     }
     rqst = Request(cls.session, 'POST', '/admin/graphql')
     rqst.set_json({
         'query': q,
         'variables': variables,
     })
     async with rqst.fetch() as resp:
         data = await resp.json()
         return data['create_keypair']
예제 #21
0
 async def build(cls, **kwargs) -> dict:
     rqst = Request(cls.session, 'POST', '/image/import')
     rqst.set_json(kwargs)
     async with rqst.fetch() as resp:
         return await resp.json()