Initial Commit

This commit is contained in:
Tanishq Dubey 2022-08-12 15:23:42 -04:00
commit 7b1706b2dd
No known key found for this signature in database
GPG Key ID: 0D0F75C0132BFC41
7 changed files with 365 additions and 0 deletions

160
.gitignore vendored Normal file
View File

@ -0,0 +1,160 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

10
Dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM docker.co.clearstreet.io/clst/clst-python:3.9.5-slim-buster
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD [ "python", "./main.py" ]

5
config/localkube.yaml Normal file
View File

@ -0,0 +1,5 @@
---
aws:
access_key: fake
secret_key: fake
endpoint_url: http://aws:4566

129
main.py Normal file
View File

@ -0,0 +1,129 @@
import os
import boto3
from flask import Flask, send_file, render_template, redirect
from gestalt import Gestalt
from clearstreet.logger import create_logger
def sanitize_key(key):
return key.replace("/", "-")
def rebuild_key(key):
return key.replace("-", "/")
def get_path(key):
s = key.split("/")
return "/".join(s[:len(s) - 1])
def get_filename(key):
s = key.split("/")
return s[len(s) - 1]
def build_s3_client(config: Gestalt):
session = boto3.Session()
access = config.get_string("aws.access_key")
secret = config.get_string("aws.secret_key")
url = config.get_string("aws.endpoint_url", 's3.amazonaws.com')
s3 = session.client(
service_name="s3",
aws_access_key_id=access,
aws_secret_access_key=secret,
endpoint_url=url,
)
return s3
def list_buckets(client):
ret = []
list = client.list_buckets()['Buckets']
for bucket in list:
ret.append(bucket["Name"])
ret.sort()
return ret
def list_in_bucket(client, bucket, prefix):
ret = []
items = []
if prefix is None or len(prefix) == 0:
items = client.list_objects_v2(Bucket=bucket, Delimiter="/")
else:
items = client.list_objects_v2(Bucket=bucket, Prefix=f"{prefix}/", Delimiter="/")
for item in items.get('Contents', []):
if item.get('Key', None) is not None:
ret.append(item['Key'])
ret.sort()
dirs = []
for item in items.get('CommonPrefixes', []):
if item.get('Prefix', None) is not None:
dirs.append(item['Prefix'])
dirs.sort()
return ret, dirs
def download_object(client, bucket_name, key):
key = rebuild_key(key)
filename = "/tmp" + get_filename(key)
client.download_file(Bucket=bucket_name, Key=key, Filename=filename)
return filename
env = os.environ.get('ENV', 'localkube')
logger = create_logger("q1")
app = Flask(__name__)
logger.info("loading configurations", env=env)
g = Gestalt()
g.add_config_file(f'./config/{env}.yaml')
g.build_config()
g.auto_env()
s3client = build_s3_client(g)
@app.route('/download/<bucket>/<path:path>')
def download(bucket, path):
global s3client
fname = download_object(s3client, bucket, path)
return send_file(fname, as_attachment=True)
@app.route('/browse/<bucket>', defaults={'path': ''})
@app.route('/browse/<bucket>/', defaults={'path': ''})
@app.route('/browse/<bucket>/<path:path>')
@app.route('/browse/<bucket>/<path:path>/')
def withinBucket(bucket, path):
global s3client
logger.info("inside bucket", bucket=bucket, path=path)
items, dirs = list_in_bucket(s3client, bucket, path)
return render_template('browser.html', items=items, dirs=dirs, bucket=bucket, path=path)
@app.route('/browse')
@app.route('/browse/')
def sendhome():
return redirect("/", code=302)
@app.route('/')
def root():
global s3client
buckets = list_buckets(s3client)
return render_template('index.html', buckets=buckets)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8081, debug=True)

5
requirements.txt Normal file
View File

@ -0,0 +1,5 @@
Flask==2.1.2
clearstreet.logger==2.0.2
boto3==1.24.47
botocore==1.27.48
gestalt-cfg==3.0.0

31
templates/browser.html Normal file
View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--Import Google Icon Font-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Q1</title>
</head>
<body>
<h1>Q1: A Simple S3 Browser</h1>
<h3>Directories</h3>
<ul>
{% for item in dirs %}
<li><a href="/browse/{{bucket}}/{{item}}">{{item}}</a></li>
{% endfor %}
</ul>
<h3>Files</h3>
<ul>
{% for item in items %}
<li>{{item}} -- <a href="/download/{{bucket}}/{{item}}">Download</a></li>
{% endfor %}
</ul>
<a href="../"><b>Back</b></a>
<script type="text/javascript" src="js/materialize.min.js"></script>
</body>
</html>

25
templates/index.html Normal file
View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--Import Google Icon Font-->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Q1</title>
</head>
<body>
<h1>Q1: A Simple S3 Browser</h1>
<ul>
{% for bucket in buckets %}
<li><a href="/browse/{{bucket}}">{{bucket}}</a></li>
{% endfor %}
</ul>
<script type="text/javascript" src="js/materialize.min.js"></script>
</body>
</html>