|
13 | 13 | import tempfile |
14 | 14 | from flask_bcrypt import Bcrypt |
15 | 15 | from flask_sqlalchemy import SQLAlchemy |
| 16 | +from flask_migrate import Migrate |
16 | 17 |
|
17 | 18 | from flask import request, jsonify, Flask, make_response |
18 | 19 | from flask_restful import Resource, abort, Api |
|
22 | 23 | from pbench.server import PbenchServerConfig |
23 | 24 | from pbench.common.exceptions import BadConfig |
24 | 25 | from pbench.server.utils import filesize_bytes |
25 | | -from pbench.server.api.resources.pbench_users import RegisterUser, LoginAPI, LogoutAPI, GetUser |
| 26 | +from pbench.server.api.resources.pbench_users import ( |
| 27 | + RegisterUser, |
| 28 | + LoginAPI, |
| 29 | + LogoutAPI, |
| 30 | + GetUser, |
| 31 | + DeleteUser, |
| 32 | +) |
26 | 33 |
|
27 | 34 | ALLOWED_EXTENSIONS = {"xz"} |
28 | 35 |
|
29 | | -app = None |
30 | | -bcrypt = None |
31 | | -db = None |
32 | 36 |
|
33 | | -"""" |
34 | | -A storage engine to save revoked tokens. if speed is the primary concern, redis is a good option. but if data |
35 | | -persistence is more important, postgres can be another good option too. Here I am using an in memory store to get |
36 | | -something working. |
37 | | -""" |
38 | | -blacklist = set() |
39 | | - |
40 | | - |
41 | | -def allowed_file(filename): |
42 | | - """Check if the file has the correct extension.""" |
43 | | - try: |
44 | | - fn = filename.rsplit(".", 1)[1].lower() |
45 | | - except IndexError: |
46 | | - return False |
47 | | - allowed = "." in filename and fn in ALLOWED_EXTENSIONS |
48 | | - return allowed |
49 | | - |
50 | | - |
51 | | -def register_endpoints(api, app): |
52 | | - """Register flask endpoints with the corresponding resource classes |
53 | | - to make the APIs active.""" |
54 | | - |
55 | | - api.add_resource( |
56 | | - Upload, f"{app.config['REST_URI']}/upload/ctrl/<string:controller>" |
57 | | - ) |
58 | | - api.add_resource(HostInfo, f"{app.config['REST_URI']}/host_info") |
59 | | - api.add_resource(Elasticsearch, f"{app.config['REST_URI']}/elasticsearch") |
60 | | - api.add_resource(GraphQL, f"{app.config['REST_URI']}/graphql") |
61 | | - api.add_resource(RegisterUser, f"{app.config['REST_URI']}/register") |
62 | | - api.add_resource(LoginAPI, f"{app.config['REST_URI']}/login") |
63 | | - api.add_resource(LogoutAPI, f"{app.config['REST_URI']}/logout") |
64 | | - api.add_resource(GetUser, f"{app.config['REST_URI']}/user") |
65 | | - |
66 | | - |
67 | | -def create_app(): |
68 | | - """Create Flask app with defined resource endpoints.""" |
69 | | - |
70 | | - global app, db, bcrypt, blacklist |
71 | | - |
72 | | - cfg_name = os.environ.get("_PBENCH_SERVER_CONFIG") |
73 | | - if not cfg_name: |
74 | | - print( |
75 | | - f"{__name__}: ERROR: No config file specified; set" |
76 | | - " _PBENCH_SERVER_CONFIG", |
77 | | - file=sys.stderr, |
| 37 | +class App: |
| 38 | + app = None |
| 39 | + bcrypt = None |
| 40 | + db = None |
| 41 | + blacklist = None |
| 42 | + |
| 43 | + @staticmethod |
| 44 | + def allowed_file(filename): |
| 45 | + """Check if the file has the correct extension.""" |
| 46 | + try: |
| 47 | + fn = filename.rsplit(".", 1)[1].lower() |
| 48 | + except IndexError: |
| 49 | + return False |
| 50 | + allowed = "." in filename and fn in ALLOWED_EXTENSIONS |
| 51 | + return allowed |
| 52 | + |
| 53 | + @staticmethod |
| 54 | + def register_endpoints(api, app, db, bcrypt, blacklist): |
| 55 | + """Register flask endpoints with the corresponding resource classes |
| 56 | + to make the APIs active.""" |
| 57 | + |
| 58 | + api.add_resource( |
| 59 | + Upload, f"{app.config['REST_URI']}/upload/ctrl/<string:controller>" |
| 60 | + ) |
| 61 | + api.add_resource(HostInfo, f"{app.config['REST_URI']}/host_info") |
| 62 | + api.add_resource(Elasticsearch, f"{app.config['REST_URI']}/elasticsearch") |
| 63 | + api.add_resource(GraphQL, f"{app.config['REST_URI']}/graphql") |
| 64 | + api.add_resource( |
| 65 | + RegisterUser, f"{app.config['REST_URI']}/user", resource_class_args=(app, db) |
| 66 | + ) |
| 67 | + api.add_resource( |
| 68 | + LoginAPI, f"{app.config['REST_URI']}/session", resource_class_args=(app, bcrypt) |
78 | 69 | ) |
79 | | - sys.exit(1) |
80 | | - |
81 | | - try: |
82 | | - config = PbenchServerConfig(cfg_name) |
83 | | - except BadConfig as e: |
84 | | - print(f"{__name__}: {e} (config file {cfg_name})", file=sys.stderr) |
85 | | - sys.exit(1) |
86 | | - |
87 | | - app = Flask(__name__) |
88 | | - api = Api(app) |
89 | | - |
90 | | - app.logger = get_pbench_logger(__name__, config) |
91 | | - app.config_server = config.conf["pbench-server"] |
92 | | - app.config_elasticsearch = config.conf["elasticsearch"] |
93 | | - app.config_graphql = config.conf["graphql"] |
94 | | - |
95 | | - prdp = app.config_server.get("pbench-receive-dir-prefix") |
96 | | - if not prdp: |
97 | | - app.logger.error("Missing config variable for pbench-receive-dir-prefix") |
98 | | - sys.exit(1) |
99 | | - try: |
100 | | - upload_directory = Path(f"{prdp}-002").resolve(strict=True) |
101 | | - except FileNotFoundError: |
102 | | - app.logger.exception("pbench-receive-dir-prefix does not exist on the host") |
103 | | - sys.exit(1) |
104 | | - except Exception: |
105 | | - app.logger.exception( |
106 | | - "Exception occurred during setting up the upload directory on the host" |
| 70 | + api.add_resource( |
| 71 | + LogoutAPI, |
| 72 | + f"{app.config['REST_URI']}/session", |
| 73 | + resource_class_args=(app, blacklist), |
| 74 | + ) |
| 75 | + api.add_resource( |
| 76 | + GetUser, |
| 77 | + f"{app.config['REST_URI']}/user/<string:username>", |
| 78 | + resource_class_args=(app), |
| 79 | + ) |
| 80 | + api.add_resource( |
| 81 | + DeleteUser, |
| 82 | + f"{app.config['REST_URI']}/user/<string:username>", |
| 83 | + resource_class_args=(app, db), |
| 84 | + ) |
| 85 | + |
| 86 | + def create_app(self): |
| 87 | + """Create Flask app with defined resource endpoints.""" |
| 88 | + |
| 89 | + cfg_name = os.environ.get("_PBENCH_SERVER_CONFIG") |
| 90 | + if not cfg_name: |
| 91 | + print( |
| 92 | + f"{__name__}: ERROR: No config file specified; set" |
| 93 | + " _PBENCH_SERVER_CONFIG", |
| 94 | + file=sys.stderr, |
| 95 | + ) |
| 96 | + sys.exit(1) |
| 97 | + |
| 98 | + try: |
| 99 | + config = PbenchServerConfig(cfg_name) |
| 100 | + except BadConfig as e: |
| 101 | + print(f"{__name__}: {e} (config file {cfg_name})", file=sys.stderr) |
| 102 | + sys.exit(1) |
| 103 | + |
| 104 | + app = Flask(__name__) |
| 105 | + api = Api(app) |
| 106 | + |
| 107 | + app.logger = get_pbench_logger(__name__, config) |
| 108 | + app.config_server = config.conf["pbench-server"] |
| 109 | + app.config_elasticsearch = config.conf["elasticsearch"] |
| 110 | + app.config_graphql = config.conf["graphql"] |
| 111 | + |
| 112 | + prdp = app.config_server.get("pbench-receive-dir-prefix") |
| 113 | + if not prdp: |
| 114 | + app.logger.error("Missing config variable for pbench-receive-dir-prefix") |
| 115 | + sys.exit(1) |
| 116 | + try: |
| 117 | + upload_directory = Path(f"{prdp}-002").resolve(strict=True) |
| 118 | + except FileNotFoundError: |
| 119 | + app.logger.exception("pbench-receive-dir-prefix does not exist on the host") |
| 120 | + sys.exit(1) |
| 121 | + except Exception: |
| 122 | + app.logger.exception( |
| 123 | + "Exception occurred during setting up the upload directory on the host" |
| 124 | + ) |
| 125 | + sys.exit(1) |
| 126 | + else: |
| 127 | + app.upload_directory = upload_directory |
| 128 | + |
| 129 | + app.config["PORT"] = app.config_server.get("rest_port") |
| 130 | + app.config["VERSION"] = app.config_server.get("rest_version") |
| 131 | + app.config["MAX_CONTENT_LENGTH"] = filesize_bytes( |
| 132 | + app.config_server.get("rest_max_content_length") |
107 | 133 | ) |
108 | | - sys.exit(1) |
109 | | - else: |
110 | | - app.upload_directory = upload_directory |
| 134 | + app.config["REST_URI"] = app.config_server.get("rest_uri") |
| 135 | + app.config["LOG"] = app.config_server.get("rest_log") |
| 136 | + app.config["BIND_HOST"] = app.config_server.get("bind_host") |
| 137 | + app.config["WORKERS"] = app.config_server.get("workers") |
111 | 138 |
|
112 | | - app.config["PORT"] = app.config_server.get("rest_port") |
113 | | - app.config["VERSION"] = app.config_server.get("rest_version") |
114 | | - app.config["MAX_CONTENT_LENGTH"] = filesize_bytes( |
115 | | - app.config_server.get("rest_max_content_length") |
116 | | - ) |
117 | | - app.config["REST_URI"] = app.config_server.get("rest_uri") |
118 | | - app.config["BIND_HOST"] = app.config_server.get("bind_host") |
119 | | - app.config["WORKERS"] = app.config_server.get("workers") |
| 139 | + # postgresql specific configuration |
| 140 | + app.config["DB_SECRET_KEY"] = os.getenv("SECRET_KEY", "my_precious") |
| 141 | + app.config["BCRYPT_LOG_ROUNDS"] = app.config_server.get("bycrypt_log_rounds") |
| 142 | + app.config["POSTGRES_DB_URI"] = app.config_server.get("postgres_db_uri") |
120 | 143 |
|
121 | | - # postgresql specific configuration |
122 | | - app.config["DB_SECRET_KEY"] = os.getenv("SECRET_KEY", "my_precious") |
123 | | - app.config["BCRYPT_LOG_ROUNDS"] = app.config_server.get("bycrypt_log_rounds") |
124 | | - app.config["POSTGRES_DB_URI"] = app.config_server.get("postgres_db_uri") |
| 144 | + bcrypt = Bcrypt(app) |
| 145 | + db = SQLAlchemy(app) |
| 146 | + migrate = Migrate(db) |
125 | 147 |
|
126 | | - bcrypt = Bcrypt(app) |
127 | | - db = SQLAlchemy(app) |
| 148 | + """" |
| 149 | + A storage engine to save revoked tokens. if speed is the primary concern, redis is a good option. but if data |
| 150 | + persistence is more important, postgres can be another good option too. Here I am using an in memory store to get |
| 151 | + something working. |
| 152 | + """ |
| 153 | + blacklist = set() |
128 | 154 |
|
129 | | - register_endpoints(api, app) |
| 155 | + self.register_endpoints(api, app, db, bcrypt, blacklist) |
130 | 156 |
|
131 | | - return app |
| 157 | + return app |
132 | 158 |
|
133 | 159 |
|
134 | 160 | def _build_cors_preflight_response(): |
@@ -327,7 +353,7 @@ def put(self, controller): |
327 | 353 | md5sum = request.headers.get("Content-MD5") |
328 | 354 |
|
329 | 355 | app.logger.debug("Receiving file: {}", filename) |
330 | | - if not allowed_file(filename): |
| 356 | + if not App.allowed_file(filename): |
331 | 357 | app.logger.debug( |
332 | 358 | f"Tarfile upload: Bad file extension received for file {filename}" |
333 | 359 | ) |
|
0 commit comments