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

Develop #2

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
114 changes: 114 additions & 0 deletions cc_cloud/routes/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,23 @@ def cloud_routes(app, auth, cloud_service):
Creates the cloud webinterface endpoints.

:param app: The flask app to attach to
:type app: flask.Flask
:param auth: The authorization module to use
:type auth: Auth
:param cloud_service: The cloud service module to use.
:type cloud_service: CloudService
"""

@app.route('/file', methods=['GET'])
def download_file():
"""
Endpoint for downloading a file.

:param path: The path of the file to download.
:type path: str
:return: The file as an attachment if it exists, or an appropriate error message.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)
path = request.args.get('path')

Expand All @@ -31,6 +42,14 @@ def download_file():

@app.route('/file', methods=['PUT'])
def upload_file():
"""
Endpoint for uploading a file.

:param files: The uploaded file(s) to be saved.
:type files: werkzeug.datastructures.FileStorage or dict[str, werkzeug.datastructures.FileStorage]
:return: The response indicating the success of the file upload.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)

cloud_service.upload_file(user, request.files)
Expand All @@ -40,6 +59,14 @@ def upload_file():

@app.route('/file', methods=['DELETE'])
def delete_file():
"""
Endpoint for deleting a file.

:param path: The path of the file to delete.
:type path: str
:return: The response indicating the success of the file deletion.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)
path = request.args.get('path')

Expand All @@ -49,8 +76,87 @@ def delete_file():
return create_flask_response(response_string, auth, user.authentication_cookie)


@app.route('/public_key', methods=['PUT'])
def add_public_key():
"""
Endpoint for adding a public key.

:param key: The public key to add.
:type key: str
:return: The response indicating the success of adding the public key.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)
public_key = request.args.get('key')

added = cloud_service.set_local_user_authorized_key(user, public_key)
response_string = 'ok' if added else 'public key not valid'

return create_flask_response(response_string, auth, user.authentication_cookie)


@app.route('/size', methods=['GET'])
def get_current_size():
"""
Endpoint for retrieving the current storage usage.

:return: The current storage size in bytes.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)

current_size = cloud_service.get_storage_usage(user)

return create_flask_response(current_size, auth, user.authentication_cookie)


@app.route('/size_limit', methods=['GET'])
def get_size_limit():
"""
Endpoint for retrieving the size limit.

:return: The size limit in bytes.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)

size_limit = cloud_service.get_size_limit(user)

return create_flask_response(size_limit, auth, user.authentication_cookie)


@app.route('/size_limit', methods=['PUT'])
def set_size_limit():
"""
Endpoint for setting the size limit.

:param username: The username for which to set the size limit.
:type username: str
:param size: The new size limit in bytes.
:type size: str
:return: The response indicating the success of changing the size limit.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)
change_user = request.args.get('username')
size = request.args.get('size')

edited = cloud_service.set_size_limit(user, change_user, int(size))
response_string = 'ok' if edited else 'could not change the size'

return create_flask_response(response_string, auth, user.authentication_cookie)


@app.route('/create_user', methods=['GET'])
def create_user():
"""
Endpoint for creating a user.

:param username: The username to create.
:type username: str
:return: The response indicating the success of creating the user.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)
create_username = request.args.get('username')

Expand All @@ -62,6 +168,14 @@ def create_user():

@app.route('/remove_user', methods=['GET'])
def remove_user():
"""
Endpoint for removing a user.

:param username: The username to remove.
:type username: str
:return: The response indicating the success of removing the user.
:rtype: flask.Response
"""
user = auth.verify_user(request.authorization, request.cookies, request.remote_addr)
remove_username = request.args.get('username')

Expand Down
95 changes: 89 additions & 6 deletions cc_cloud/service/cloud_service.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

from sshpubkeys import SSHKey
from cc_cloud.service.filesystem_service import FilesystemService
from cc_cloud.service.file_service import FileService
from cc_cloud.system.local_user import LocalUser
Expand Down Expand Up @@ -41,7 +41,10 @@ def get_user_ref(self, user):
:return: user reference
:rtype: str
"""
return self.user_prefix + '-' + user.username
if isinstance(user, Auth.User):
return self.user_prefix + '-' + user.username
elif isinstance(user, str):
return self.user_prefix + '-' + user


def local_user_exists_or_create(self, user):
Expand Down Expand Up @@ -75,6 +78,10 @@ def add_local_user_to_db(self, username, ssh_user, ssh_password, size_limit):
self.mongo.db['cloud_users'].update_one({'username': username}, {'$set': cloud_users}, upsert=True)


def get_local_user_from_db(self, username):
return self.mongo.db['cloud_users'].find_one({'username': username})


## cloud storage actions

def file_action(self, user, func, *args):
Expand Down Expand Up @@ -141,13 +148,91 @@ def set_local_user_authorized_key(self, user, pub_key):
:param pub_key: public ssh-key, that will be added to the authorized_keys file
:type pub_key: str
"""
try:
ssh = SSHKey(pub_key)
ssh.parse()
except Exception:
return False

_, local_user = self.local_user_exists_or_create(user)
local_user.set_authorized_key(pub_key)
return True


def get_storage_usage(self, user):
"""
Get the current storage usage for a user.

:param user: The user for whom to retrieve the storage usage.
:type user: cc_agency.broker.auth.Auth.User
:return: The storage usage in bytes.
:rtype: int
"""
user_ref = self.get_user_ref(user)
try:
return self.filesystem_service.get_storage_usage(user_ref)
except TypeError:
return 0


def get_size_limit(self, user):
"""
Get the size limit for a user.

:param user: The user for whom to retrieve the size limit.
:type user: cc_agency.broker.auth.Auth.User
:return: The size limit in bytes.
:rtype: int
"""
user_ref = self.get_user_ref(user)
return self.filesystem_service.get_size(user_ref)


## only for admin users

def set_size_limit(self, user, change_user, size):
"""
Set the size limit for a user.

:param user: The user making the size limit change. Should be an admin user.
:type user: cc_agency.broker.auth.Auth.User
:param change_user: The user for whom the size limit will be changed.
:type change_user: cc_agency.broker.auth.Auth.User
:param size: The new size limit in bytes.
:type size: int
:return: True if the size limit was successfully changed, False otherwise.
:rtype: bool
"""
if not user.is_admin:
return False

db_user = self.get_local_user_from_db(change_user)
if not db_user:
return False

change_user_ref = self.get_user_ref(change_user)
current_size_limit = self.filesystem_service.get_size(change_user_ref)
if size > current_size_limit:
self.filesystem_service.increse_size(change_user_ref, size)
elif size < current_size_limit:
self.filesystem_service.reduce_size(change_user_ref, size)

self.mongo.db['cloud_users'].update_one({'username': change_user}, {'$set': {'size_limit': size}}, upsert=True)

return True


def create_user(self, user, create_username):
"""
Create a new user.

:param user: The user creating the new user. Should be an admin user.
:type user: cc_agency.broker.auth.Auth.User
:param create_username: The username for the new user.
:type create_username: str
:return: True if the user was successfully created, False otherwise.
:rtype: bool
"""
if not user.is_admin:
return False

Expand All @@ -172,10 +257,8 @@ def remove_user(self, user, remove_username):
if not user.is_admin:
return False

remove_user = Auth.User(remove_username, False)
user_ref = self.get_user_ref(remove_user)

self.mongo.db['cloud_users'].delete_one({'username': remove_user.username})
user_ref = self.get_user_ref(remove_username)
self.mongo.db['cloud_users'].delete_one({'username': remove_username})

self.filesystem_service.umount(user_ref)
self.filesystem_service.delete(user_ref)
Expand Down
22 changes: 18 additions & 4 deletions cc_cloud/service/filesystem_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def create(self, fs_name, size=None):

:param fs_name: Creates a filesystem with the name fs_name
:type fs_name: str
:param size: Size of the filesystem, defaults to None
:param size: Size (bytes) of the filesystem, defaults to None
:type size: int, optional
"""
filepath = self.get_filepath(fs_name)
Expand Down Expand Up @@ -134,7 +134,7 @@ def increse_size(self, fs_name, size):

:param fs_name: Increse size of the filesystem with the name fs_name
:type fs_name: str
:param size: The size of the file system is set to the specified size
:param size: The size (bytes) of the file system is set to the specified size
:type size: int
"""
filepath = self.get_filepath(fs_name)
Expand All @@ -150,7 +150,7 @@ def reduce_size(self, fs_name, size):

:param fs_name: Reduce size of the filesystem with the name fs_name
:type fs_name: str
:param size: The size of the file system is set to the specified size
:param size: The size (bytes) of the file system is set to the specified size.
:type size: int
"""
if self.is_mounted(fs_name):
Expand All @@ -159,7 +159,7 @@ def reduce_size(self, fs_name, size):
self.create(fs_name, size)

def get_size(self, fs_name):
"""Get the size of the filesystem.
"""Get the size limit of the filesystem in bytes.

:param fs_name: Get size of the filesystem with the name fs_name
:type fs_name: str
Expand All @@ -169,6 +169,20 @@ def get_size(self, fs_name):
filepath = self.get_filepath(fs_name)
return os.path.getsize(filepath)

def get_storage_usage(self, fs_name):
"""Get the current usage of the cloud storage in bytes.

:param fs_name: Get usage of the cloud storage with the name fs_name
:type fs_name: str
:return: Usage of cloud storage
:rtype: int
"""
if not self.is_mounted(fs_name):
self.mount(fs_name)
mountpoint = self.get_mountpoint(fs_name)
total, used, free = shutil.disk_usage(mountpoint)
return used

def get_loop_device(self, filepath):
"""Get the loop device of the mounted filesystem.

Expand Down
Loading