Skip to content

Added support for IAM endpoints #552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: proj/iam
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions linode_api4/groups/iam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from typing import Any, Dict, List, Optional, Union

from linode_api4.errors import UnexpectedResponseError
from linode_api4.groups import Group
from linode_api4.objects import EntityAccess, LinodeEntity


class IAMGroup(Group):
def role_permissions(self):
"""
Returns the permissions available on the account assigned to any user of the account.

This is intended to be called off of the :any:`LinodeClient`
class, like this::

permissions = client.role_permissions()

API Documentation: TODO

:returns: The JSON role permissions for the account.
"""
return self.client.get("/iam/role-permissions", model=self)

def role_permissions_user_get(self, username):
"""
Returns the permissions available on the account assigned to the specified user.

This is intended to be called off of the :any:`LinodeClient`
class, like this::

permissions = client.role_permissions_user_get("myusername")

API Documentation: TODO

:returns: The JSON role permissions for the user.
"""
return self.client.get(
f"/iam/users/{username}/role-permissions", model=self
)

def role_permissions_user_set(
self,
username,
account_access: Optional[List[str]] = None,
entity_access: Optional[
Union[List[EntityAccess], Dict[str, Any]]
] = None,
):
"""
Assigns the specified permissions to the specified user, and returns them.

This is intended to be called off of the :any:`LinodeClient`
class, like this::

permissions = client.role_permissions_user_set("muusername")

API Documentation: TODO

:returns: The JSON role permissions for the user.
"""
params = {
"account_access": account_access,
"entity_access": entity_access,
}

result = self.client.put(
f"/iam/users/{username}/role-permissions",
data=params,
)

if "account_access" not in result:
raise UnexpectedResponseError(
"Unexpected response updating role permissions!", json=result
)

return result

def entities(self, *filters):
"""
Returns the current entities of the account.

This is intended to be called off of the :any:`LinodeClient`
class, like this::

permissions = client.entities()

API Documentation: TODO

:param filters: Any number of filters to apply to this query.
See :doc:`Filtering Collections</linode_api4/objects/filtering>`
for more details on filtering.

:returns: A list of entities that match the query.
:rtype: PaginatedList of Entity
"""
return self.client._get_and_filter(
LinodeEntity, *filters, endpoint="/entities"
)
4 changes: 4 additions & 0 deletions linode_api4/linode_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
)
from linode_api4.objects import Image, and_

from .groups.iam import IAMGroup
from .groups.placement import PlacementAPIGroup
from .paginated_list import PaginatedList

Expand Down Expand Up @@ -171,6 +172,9 @@ def __init__(
#: Access methods related to Managed Databases - see :any:`DatabaseGroup` for more information.
self.database = DatabaseGroup(self)

#: Access methods related to IAM - see :any:`IAMGroup` for more information.
self.iam = IAMGroup(self)

#: Access methods related to NodeBalancers - see :any:`NodeBalancerGroup` for more information.
self.nodebalancers = NodeBalancerGroup(self)

Expand Down
1 change: 1 addition & 0 deletions linode_api4/objects/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .serializable import JSONObject
from .filtering import and_, or_
from .region import Region
from .iam import *
from .image import Image
from .linode import *
from .volume import *
Expand Down
34 changes: 34 additions & 0 deletions linode_api4/objects/iam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import List

from linode_api4.objects.base import Base, JSONObject, Property


class LinodeEntity(Base):
"""
An Entity represents an entity of the account.

Currently the Entity can only be retrieved by listing, i.e.:
entities = client.iam.entities()

API documentation: TODO
"""

properties = {
"id": Property(identifier=True),
"label": Property(),
"type": Property(),
}


@dataclass
class EntityAccess(JSONObject):
"""
EntityAccess represents a user's access to an entity.
"""

id: int
type: str
roles: List[str]
77 changes: 77 additions & 0 deletions test/fixtures/entities.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"data": [
{
"id": 7,
"label": "linode7",
"type": "linode"
},
{
"id": 10,
"label": "linode10",
"type": "linode"
},
{
"id": 1,
"label": "no_devices",
"type": "firewall"
},
{
"id": 2,
"label": "active_with_nodebalancer",
"type": "firewall"
},
{
"id": 1,
"label": "nodebalancer-active",
"type": "nodebalancer"
},
{
"id": 1,
"label": "active",
"type": "longview"
},
{
"id": 3,
"label": "LongviewClientTest",
"type": "longview"
},
{
"id": 1,
"label": "linDomTest1.com",
"type": "domain"
},
{
"id": 1,
"label": "API Test",
"type": "stackscript"
},
{
"id": 1,
"label": "Test image - mine",
"type": "image"
},
{
"id": 3,
"label": "Test image - mine - creating",
"type": "image"
},
{
"id": 1,
"label": "volume1",
"type": "volume"
},
{
"id": 1,
"label": "mongo_cluster",
"type": "database"
},
{
"id": 3,
"label": "empty-vpc",
"type": "vpc"
}
],
"page": 1,
"pages": 1,
"results": 14
}
81 changes: 81 additions & 0 deletions test/fixtures/iam_role-permissions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"account_access": [
{
"type": "account",
"roles": [
{
"name": "account_admin",
"description": "Access to perform any supported action on all entities of the account",
"permissions": [
"create_linode",
"update_linode",
"update_firewall"
]
}
]
},
{
"type": "linode",
"roles": [
{
"name": "account_linode_admin",
"description": "Access to perform any supported action on all linode instances of the account",
"permissions": [
"create_linode",
"update_linode",
"delete_linode"
]
}
]
},
{
"type": "firewall",
"roles": [
{
"name": "firewall_creator",
"description": "Access to create a firewall instance",
"permissions": [
"update_linode",
"view_linode"
]
}
]
}
],
"entity_access": [
{
"type": "linode",
"roles": [
{
"name": "linode_contributor",
"description": "Access to update a linode instance",
"permissions": [
"update_linode",
"view_linode"
]
}
]
},
{
"type": "firewall",
"roles": [
{
"name": "firewall_viewer",
"description": "Access to view a firewall instance",
"permissions": [
"update_linode",
"view_linode"
]
},
{
"name": "firewall_admin",
"description": "Access to perform any supported action on a firewall instance",
"permissions": [
"update_linode",
"view_linode"
]
}
]
}
]
}
23 changes: 23 additions & 0 deletions test/fixtures/iam_users_myusername_role-permissions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"account_access": [
"account_linode_admin",
"linode_creator",
"firewall_creator"
],
"entity_access": [
{
"id": 1,
"type": "linode",
"roles": [
"linode_contributor"
]
},
{
"id": 1,
"type": "firewall",
"roles": [
"firewall_admin"
]
}
]
}
Loading