Skip to content
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

Backup #314

Merged
merged 7 commits into from
Nov 5, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
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
24 changes: 21 additions & 3 deletions fusillade/clouddirectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,15 @@ def list_policy_attachments(self, policy: str, **kwargs) -> Iterator[str]:
**kwargs
)

def list_object_parent_paths(self, object_ref: str, **kwargs) -> Iterator[str]:
return _paging_loop(cd_client.list_object_parent_paths,
'PathToObjectIdentifiersList',
DirectoryArn=self._dir_arn,
ObjectReference={'Selector': object_ref},
MaxResults=self._page_limit,
**kwargs
)

@retry(**cd_read_retry_parameters)
def _list_typed_links(self,
func: Callable,
Expand Down Expand Up @@ -423,7 +432,7 @@ def list_incoming_typed_links(

@staticmethod
def _make_ref(i):
return '$' + i
return i if i[0] == '$' else '$' + i

def create_object(self, link_name: str, facet_type: str, obj_type: str, **kwargs) -> str:
"""
Expand Down Expand Up @@ -1040,7 +1049,7 @@ class CloudNode:
Contains shared code across the different types of nodes stored in Fusillade CloudDirectory
"""
_attributes = ["name"] # the different attributes of a node stored
_facet = 'LeafNode'
_facet = 'LeafFacet'
object_type = 'node'

def __init__(self,
Expand Down Expand Up @@ -1270,6 +1279,15 @@ def _exists(cls, nodes: List[str]):
except cd_client.exceptions.ResourceNotFoundException:
raise FusilladeBadRequestException(f"One or more {cls.object_type} does not exist.")

def list_owners(self, incoming=True):
get_links = self.cd.list_incoming_typed_links if incoming else self.cd.list_outgoing_typed_links
object_selection = 'SourceObjectReference' if incoming else 'TargetObjectReference'
return [
type_link[object_selection]['Selector']
for type_link in
get_links(self.object_ref, filter_typed_link='ownership_link')
]


class PolicyMixin:
"""Adds policy support to a cloudNode"""
Expand Down Expand Up @@ -1356,7 +1374,7 @@ def get_policy(self, policy_type: str = 'IAMPolicy'):
self.attached_policies[policy_type] = attrs['policy_document'].decode("utf-8")
except cd_client.exceptions.ResourceNotFoundException:
pass
return self.attached_policies.get(policy_type, '')
return self.attached_policies.get(policy_type, '{}')
else:
FusilladeHTTPException(
title='Bad Request',
Expand Down
82 changes: 82 additions & 0 deletions scripts/backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python
"""
Create a backup of Clouddirectory in AWS S3.
"""
import json
import os
import sys

pkg_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) # noqa
sys.path.insert(0, pkg_root) # noqa

from fusillade.clouddirectory import User, Group, Role


def list_node(node, field):
result, next_token = node.list_all(None, None)
while True:
for i in result[field]:
yield i
if next_token:
result, next_token = node.list_all(next_token, None)
else:
break


def backup_users():
users = []
for name in list_node(User, 'users'):
user = User(name)
info = {
'name': user.name,
'status': user.status,
'policies': [{p: json.loads(user.get_policy(p))} for p in user.allowed_policy_types],
'roles': [Role(object_ref=r).name for r in user.roles]
}
users.append(info)
print("USERS:", *users, sep='\n\t')
return users


def backup_groups():
groups = []
for name in list_node(Group, 'groups'):
group = Group(name)
info = {
'name': group.name,
'members': [User(object_ref=u).name for u in group.get_users_iter()],
'policies': [{p: json.loads(group.get_policy(p))} for p in group.allowed_policy_types],
'owners': [User(object_ref=u).name for u in group.list_owners()],
'roles': [Role(object_ref=r).name for r in group.roles]
}
groups.append(info)
print("GROUPS:", *groups, sep='\n\t')
return groups


def backup_roles():
roles = []
for name in list_node(Role, 'roles'):
role = Role(name)
info = {
'name': role.name,
'owners': [User(object_ref=u).name for u in role.list_owners()],
'policies': [{p: json.loads(role.get_policy(p))} for p in role.allowed_policy_types]
}
roles.append(info)
print("ROLES:", *roles, sep='\n\t')
return roles


def backup():
with open('backup.json', 'w') as fp:
json.dump(
dict(
users=backup_users(),
groups=backup_groups(),
roles=backup_roles()),
fp,
indent=2)


backup()
Bento007 marked this conversation as resolved.
Show resolved Hide resolved
29 changes: 29 additions & 0 deletions tests/test_backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env python
# coding: utf-8

"""
Functional Test of the API
"""
import json
import os
import sys
import unittest

from furl import furl

pkg_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) # noqa
sys.path.insert(0, pkg_root) # noqa

from tests import eventually
from tests.base_api_test import BaseAPITest
from tests.common import get_auth_header, service_accounts


class TestApi(BaseAPITest, unittest.TestCase):

# TODO we need a location to backup too
# TODO we need backup format


if __name__ == '__main__':
unittest.main()