diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2020-10-28 11:38:11 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-28 11:38:11 +0100 |
| commit | bb03ab6a934eaf29cea86e877c4b2024f068dd1c (patch) | |
| tree | 761afe2c0f26a44d75cb12f87c31c1ecc08105f9 | |
| parent | 38fc6fa35ca4545a6068aaa759359c271c9f5197 (diff) | |
| parent | b2cb04229766457c9eb784d1911192bceea3a032 (diff) | |
Merge pull request #51 from atlarge-research/build/migration
Migrate opendc.org to OpenDC v2
32 files changed, 166 insertions, 159 deletions
@@ -45,7 +45,7 @@ The simulator monitors the database for `QUEUED` scenarios, and simulates them a The official way to run OpenDC is using Docker. Other options include building and running locally, and building and running to deploy on a server. -For all of these options, you have to create a Google API Console project and client ID, which the OpenDC frontend and web server will use to authenticate users and requests. Follow [these steps](https://developers.google.com/identity/sign-in/web/sign-in) to make such a project. In the 'Authorized JavaScript origins' and 'Authorized redirect URI' fields, be sure to add `http://localhost:8081` and `https://localhost:3000`. Download the JSON of the OAuth 2.0 client ID you created from the Credentials tab, and specifically note the `client_id`, which you'll need to build OpenDC. +For all of these options, you have to create a Google API Console project and client ID, which the OpenDC frontend and web server will use to authenticate users and requests. Follow [these steps](https://developers.google.com/identity/sign-in/web/sign-in) to make such a project. In the 'Authorized JavaScript origins' and 'Authorized redirect URI' fields, be sure to add `http://localhost:8080` (frontend), `http://localhost:8081` (api) and `https://localhost:3000` (frontend dev). Download the JSON of the OAuth 2.0 client ID you created from the Credentials tab, and specifically note the `client_id`, which you'll need to build OpenDC. ### Installing Docker @@ -57,7 +57,7 @@ Users of Windows 10 Home and previous editions of Windows can use [Docker Toolbo _Skip this if you have GNU/Linux, Mac OS X and Windows 10 Professional._ -Open VirtualBox, navigate to the settings of your default docker VM, and go to the 'Network' tab. There, hidden in the 'Advanced' panel, is the 'Port forwarding' feature, where you can set a rule for exposing a port of the VM to the host OS. Add one from guest IP `10.0.2.15` to host IP `127.0.0.1`, both on port `8081`. This enables you to open a browser on your host OS and navigate to `http://localhost:8081`, once the server is running. +Open VirtualBox, navigate to the settings of your default docker VM, and go to the 'Network' tab. There, hidden in the 'Advanced' panel, is the 'Port forwarding' feature, where you can set a rule for exposing a port of the VM to the host OS. Add one from guest IP `10.0.2.15` to host IP `127.0.0.1`, both on port `8080` and `8081`. This enables you to open a browser on your host OS and navigate to `http://localhost:8080`, once the server is running. ### Running OpenDC @@ -82,8 +82,7 @@ OPENDC_DB_USERNAME=opendc OPENDC_DB_PASSWORD=opendcpassword OPENDC_FLASK_SECRET="This is a secret flask key, please change" OPENDC_OAUTH_CLIENT_ID=your-google-oauth-client-id -OPENDC_ROOT_DIR=/your/path/to/opendc -OPENDC_SERVER_BASE_URL=http://localhost:8081 +OPENDC_API_BASE_URL=http://localhost:8081 ``` We provide a list of default traces for you to experiment with. If you want to add others, place them in the `traces` directory and add entries to the database (see also [the database folder](database/mongo-init-opendc-db.sh)) @@ -100,4 +99,4 @@ docker-compose build docker-compose up ``` -Wait a few seconds and open `http://localhost:8081` in your browser to use OpenDC. We recommend Google Chrome for the best development experience. +Wait a few seconds and open `http://localhost:8080` in your browser to use OpenDC. We recommend Google Chrome for the best development experience. diff --git a/api/main.py b/api/main.py index 46782638..387b516a 100755 --- a/api/main.py +++ b/api/main.py @@ -27,24 +27,20 @@ if not TEST_MODE: user=os.environ['OPENDC_DB_USERNAME'], password=os.environ['OPENDC_DB_PASSWORD'], database=os.environ['OPENDC_DB'], - host=os.environ['OPENDC_DB_HOST'] if 'OPENDC_DB_HOST' in os.environ else 'localhost') + host=os.environ.get('OPENDC_DB_HOST', 'localhost')) # Set up the core app FLASK_CORE_APP = Flask(__name__) FLASK_CORE_APP.config['SECRET_KEY'] = os.environ['OPENDC_FLASK_SECRET'] FLASK_CORE_APP.json_encoder = JSONEncoder -# Set up CORS support for local setups -if 'localhost' in os.environ['OPENDC_SERVER_BASE_URL']: - CORS(FLASK_CORE_APP) +# Set up CORS support +CORS(FLASK_CORE_APP) compress = Compress() compress.init_app(FLASK_CORE_APP) -if 'OPENDC_SERVER_BASE_URL' in os.environ or 'localhost' in os.environ['OPENDC_SERVER_BASE_URL']: - SOCKET_IO_CORE = flask_socketio.SocketIO(FLASK_CORE_APP, cors_allowed_origins="*") -else: - SOCKET_IO_CORE = flask_socketio.SocketIO(FLASK_CORE_APP) +SOCKET_IO_CORE = flask_socketio.SocketIO(FLASK_CORE_APP, cors_allowed_origins="*") @FLASK_CORE_APP.route('/tokensignin', methods=['POST']) @@ -83,7 +79,7 @@ def sign_in(): return jsonify(**data) -@FLASK_CORE_APP.route('/api/<string:version>/<path:endpoint_path>', methods=['GET', 'POST', 'PUT', 'DELETE']) +@FLASK_CORE_APP.route('/<string:version>/<path:endpoint_path>', methods=['GET', 'POST', 'PUT', 'DELETE']) def api_call(version, endpoint_path): """Call an API endpoint directly over HTTP.""" diff --git a/api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py b/api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py index 84ad2830..e5982b7f 100644 --- a/api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py +++ b/api/opendc/api/v2/portfolios/portfolioId/scenarios/test_endpoint.py @@ -4,12 +4,12 @@ test_id = 24 * '1' def test_add_scenario_missing_parameter(client): - assert '400' in client.post('/api/v2/portfolios/1/scenarios').status + assert '400' in client.post('/v2/portfolios/1/scenarios').status def test_add_scenario_non_existing_portfolio(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.post(f'/api/v2/portfolios/{test_id}/scenarios', + assert '404' in client.post(f'/v2/portfolios/{test_id}/scenarios', json={ 'scenario': { 'name': 'test', @@ -41,7 +41,7 @@ def test_add_scenario_not_authorized(client, mocker): 'authorizationLevel': 'VIEW' }] }) - assert '403' in client.post(f'/api/v2/portfolios/{test_id}/scenarios', + assert '403' in client.post(f'/v2/portfolios/{test_id}/scenarios', json={ 'scenario': { 'name': 'test', @@ -102,7 +102,7 @@ def test_add_scenario(client, mocker): }) mocker.patch.object(DB, 'update', return_value=None) res = client.post( - f'/api/v2/portfolios/{test_id}/scenarios', + f'/v2/portfolios/{test_id}/scenarios', json={ 'scenario': { 'name': 'test', diff --git a/api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py b/api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py index 2d9d8d13..52f71aa4 100644 --- a/api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py +++ b/api/opendc/api/v2/portfolios/portfolioId/test_endpoint.py @@ -6,12 +6,12 @@ test_id_2 = 24 * '2' def test_get_portfolio_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get(f'/api/v2/portfolios/{test_id}').status + assert '404' in client.get(f'/v2/portfolios/{test_id}').status def test_get_portfolio_no_authorizations(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'projectId': test_id, 'authorizations': []}) - res = client.get(f'/api/v2/portfolios/{test_id}') + res = client.get(f'/v2/portfolios/{test_id}') assert '403' in res.status @@ -26,7 +26,7 @@ def test_get_portfolio_not_authorized(client, mocker): 'authorizationLevel': 'OWN' }] }) - res = client.get(f'/api/v2/portfolios/{test_id}') + res = client.get(f'/v2/portfolios/{test_id}') assert '403' in res.status @@ -41,17 +41,17 @@ def test_get_portfolio(client, mocker): 'authorizationLevel': 'EDIT' }] }) - res = client.get(f'/api/v2/portfolios/{test_id}') + res = client.get(f'/v2/portfolios/{test_id}') assert '200' in res.status def test_update_portfolio_missing_parameter(client): - assert '400' in client.put(f'/api/v2/portfolios/{test_id}').status + assert '400' in client.put(f'/v2/portfolios/{test_id}').status def test_update_portfolio_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.put(f'/api/v2/portfolios/{test_id}', json={ + assert '404' in client.put(f'/v2/portfolios/{test_id}', json={ 'portfolio': { 'name': 'test', 'targets': { @@ -74,7 +74,7 @@ def test_update_portfolio_not_authorized(client, mocker): }] }) mocker.patch.object(DB, 'update', return_value={}) - assert '403' in client.put(f'/api/v2/portfolios/{test_id}', json={ + assert '403' in client.put(f'/v2/portfolios/{test_id}', json={ 'portfolio': { 'name': 'test', 'targets': { @@ -102,7 +102,7 @@ def test_update_portfolio(client, mocker): }) mocker.patch.object(DB, 'update', return_value={}) - res = client.put(f'/api/v2/portfolios/{test_id}', json={'portfolio': { + res = client.put(f'/v2/portfolios/{test_id}', json={'portfolio': { 'name': 'test', 'targets': { 'enabledMetrics': ['test'], @@ -114,7 +114,7 @@ def test_update_portfolio(client, mocker): def test_delete_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.delete(f'/api/v2/portfolios/{test_id}').status + assert '404' in client.delete(f'/v2/portfolios/{test_id}').status def test_delete_project_different_user(client, mocker): @@ -130,7 +130,7 @@ def test_delete_project_different_user(client, mocker): }] }) mocker.patch.object(DB, 'delete_one', return_value=None) - assert '403' in client.delete(f'/api/v2/portfolios/{test_id}').status + assert '403' in client.delete(f'/v2/portfolios/{test_id}').status def test_delete_project(client, mocker): @@ -148,5 +148,5 @@ def test_delete_project(client, mocker): }) mocker.patch.object(DB, 'delete_one', return_value={}) mocker.patch.object(DB, 'update', return_value=None) - res = client.delete(f'/api/v2/portfolios/{test_id}') + res = client.delete(f'/v2/portfolios/{test_id}') assert '200' in res.status diff --git a/api/opendc/api/v2/prefabs/authorizations/test_endpoint.py b/api/opendc/api/v2/prefabs/authorizations/test_endpoint.py index 6ca0448e..6d36d428 100644 --- a/api/opendc/api/v2/prefabs/authorizations/test_endpoint.py +++ b/api/opendc/api/v2/prefabs/authorizations/test_endpoint.py @@ -66,6 +66,6 @@ def test_get_authorizations(client, mocker): }] ] mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id}) - res = client.get('/api/v2/prefabs/authorizations') + res = client.get('/v2/prefabs/authorizations') assert '200' in res.status diff --git a/api/opendc/api/v2/prefabs/prefabId/test_endpoint.py b/api/opendc/api/v2/prefabs/prefabId/test_endpoint.py index 28a71861..2daeb6bf 100644 --- a/api/opendc/api/v2/prefabs/prefabId/test_endpoint.py +++ b/api/opendc/api/v2/prefabs/prefabId/test_endpoint.py @@ -7,7 +7,7 @@ test_id_2 = 24 * '2' def test_get_prefab_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get(f'/api/v2/prefabs/{test_id}').status + assert '404' in client.get(f'/v2/prefabs/{test_id}').status def test_get_private_prefab_not_authorized(client, mocker): @@ -23,7 +23,7 @@ def test_get_private_prefab_not_authorized(client, mocker): '_id': test_id } ] - res = client.get(f'/api/v2/prefabs/{test_id}') + res = client.get(f'/v2/prefabs/{test_id}') assert '403' in res.status @@ -40,7 +40,7 @@ def test_get_private_prefab(client, mocker): '_id': test_id } ] - res = client.get(f'/api/v2/prefabs/{test_id}') + res = client.get(f'/v2/prefabs/{test_id}') assert '200' in res.status @@ -57,17 +57,17 @@ def test_get_public_prefab(client, mocker): '_id': test_id } ] - res = client.get(f'/api/v2/prefabs/{test_id}') + res = client.get(f'/v2/prefabs/{test_id}') assert '200' in res.status def test_update_prefab_missing_parameter(client): - assert '400' in client.put(f'/api/v2/prefabs/{test_id}').status + assert '400' in client.put(f'/v2/prefabs/{test_id}').status def test_update_prefab_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.put(f'/api/v2/prefabs/{test_id}', json={'prefab': {'name': 'S'}}).status + assert '404' in client.put(f'/v2/prefabs/{test_id}', json={'prefab': {'name': 'S'}}).status def test_update_prefab_not_authorized(client, mocker): @@ -84,7 +84,7 @@ def test_update_prefab_not_authorized(client, mocker): } ] mocker.patch.object(DB, 'update', return_value={}) - assert '403' in client.put(f'/api/v2/prefabs/{test_id}', json={'prefab': {'name': 'test prefab', 'rack': {}}}).status + assert '403' in client.put(f'/v2/prefabs/{test_id}', json={'prefab': {'name': 'test prefab', 'rack': {}}}).status def test_update_prefab(client, mocker): @@ -101,13 +101,13 @@ def test_update_prefab(client, mocker): } ] mocker.patch.object(DB, 'update', return_value={}) - res = client.put(f'/api/v2/prefabs/{test_id}', json={'prefab': {'name': 'test prefab', 'rack': {}}}) + res = client.put(f'/v2/prefabs/{test_id}', json={'prefab': {'name': 'test prefab', 'rack': {}}}) assert '200' in res.status def test_delete_prefab_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.delete(f'/api/v2/prefabs/{test_id}').status + assert '404' in client.delete(f'/v2/prefabs/{test_id}').status def test_delete_prefab_different_user(client, mocker): @@ -124,7 +124,7 @@ def test_delete_prefab_different_user(client, mocker): } ] mocker.patch.object(DB, 'delete_one', return_value=None) - assert '403' in client.delete(f'/api/v2/prefabs/{test_id}').status + assert '403' in client.delete(f'/v2/prefabs/{test_id}').status def test_delete_prefab(client, mocker): @@ -141,5 +141,5 @@ def test_delete_prefab(client, mocker): } ] mocker.patch.object(DB, 'delete_one', return_value={'prefab': {'name': 'name'}}) - res = client.delete(f'/api/v2/prefabs/{test_id}') + res = client.delete(f'/v2/prefabs/{test_id}') assert '200' in res.status diff --git a/api/opendc/api/v2/prefabs/test_endpoint.py b/api/opendc/api/v2/prefabs/test_endpoint.py index affa24c9..39a78c21 100644 --- a/api/opendc/api/v2/prefabs/test_endpoint.py +++ b/api/opendc/api/v2/prefabs/test_endpoint.py @@ -4,7 +4,7 @@ test_id = 24 * '1' def test_add_prefab_missing_parameter(client): - assert '400' in client.post('/api/v2/prefabs').status + assert '400' in client.post('/v2/prefabs').status def test_add_prefab(client, mocker): @@ -17,7 +17,7 @@ def test_add_prefab(client, mocker): 'datetimeLastEdited': '000', 'authorId': test_id }) - res = client.post('/api/v2/prefabs', json={'prefab': {'name': 'test prefab'}}) + res = client.post('/v2/prefabs', json={'prefab': {'name': 'test prefab'}}) assert 'datetimeCreated' in res.json['content'] assert 'datetimeLastEdited' in res.json['content'] assert 'authorId' in res.json['content'] diff --git a/api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py b/api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py index d2d7cba1..bebd6cff 100644 --- a/api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py +++ b/api/opendc/api/v2/projects/projectId/authorizations/test_endpoint.py @@ -7,7 +7,7 @@ test_id_2 = 24 * '2' def test_get_authorizations_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) mocker.patch.object(DB, 'fetch_all', return_value=None) - assert '404' in client.get(f'/api/v2/projects/{test_id}/authorizations').status + assert '404' in client.get(f'/v2/projects/{test_id}/authorizations').status def test_get_authorizations_not_authorized(client, mocker): @@ -22,7 +22,7 @@ def test_get_authorizations_not_authorized(client, mocker): }] }) mocker.patch.object(DB, 'fetch_all', return_value=[]) - res = client.get(f'/api/v2/projects/{test_id}/authorizations') + res = client.get(f'/v2/projects/{test_id}/authorizations') assert '403' in res.status @@ -38,6 +38,6 @@ def test_get_authorizations(client, mocker): }] }) mocker.patch.object(DB, 'fetch_all', return_value=[]) - res = client.get(f'/api/v2/projects/{test_id}/authorizations') + res = client.get(f'/v2/projects/{test_id}/authorizations') assert len(res.json['content']) == 0 assert '200' in res.status diff --git a/api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py b/api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py index 2a2f777d..04c699b5 100644 --- a/api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py +++ b/api/opendc/api/v2/projects/projectId/portfolios/test_endpoint.py @@ -4,12 +4,12 @@ test_id = 24 * '1' def test_add_portfolio_missing_parameter(client): - assert '400' in client.post(f'/api/v2/projects/{test_id}/portfolios').status + assert '400' in client.post(f'/v2/projects/{test_id}/portfolios').status def test_add_portfolio_non_existing_project(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.post(f'/api/v2/projects/{test_id}/portfolios', + assert '404' in client.post(f'/v2/projects/{test_id}/portfolios', json={ 'portfolio': { 'name': 'test', @@ -32,7 +32,7 @@ def test_add_portfolio_not_authorized(client, mocker): 'authorizationLevel': 'VIEW' }] }) - assert '403' in client.post(f'/api/v2/projects/{test_id}/portfolios', + assert '403' in client.post(f'/v2/projects/{test_id}/portfolios', json={ 'portfolio': { 'name': 'test', @@ -70,7 +70,7 @@ def test_add_portfolio(client, mocker): }) mocker.patch.object(DB, 'update', return_value=None) res = client.post( - f'/api/v2/projects/{test_id}/portfolios', + f'/v2/projects/{test_id}/portfolios', json={ 'portfolio': { 'name': 'test', diff --git a/api/opendc/api/v2/projects/projectId/test_endpoint.py b/api/opendc/api/v2/projects/projectId/test_endpoint.py index 43fa5eed..f9ffaf37 100644 --- a/api/opendc/api/v2/projects/projectId/test_endpoint.py +++ b/api/opendc/api/v2/projects/projectId/test_endpoint.py @@ -6,12 +6,12 @@ test_id_2 = 24 * '2' def test_get_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get(f'/api/v2/projects/{test_id}').status + assert '404' in client.get(f'/v2/projects/{test_id}').status def test_get_project_no_authorizations(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'authorizations': []}) - res = client.get(f'/api/v2/projects/{test_id}') + res = client.get(f'/v2/projects/{test_id}') assert '403' in res.status @@ -25,7 +25,7 @@ def test_get_project_not_authorized(client, mocker): 'authorizationLevel': 'OWN' }] }) - res = client.get(f'/api/v2/projects/{test_id}') + res = client.get(f'/v2/projects/{test_id}') assert '403' in res.status @@ -39,17 +39,17 @@ def test_get_project(client, mocker): 'authorizationLevel': 'EDIT' }] }) - res = client.get(f'/api/v2/projects/{test_id}') + res = client.get(f'/v2/projects/{test_id}') assert '200' in res.status def test_update_project_missing_parameter(client): - assert '400' in client.put(f'/api/v2/projects/{test_id}').status + assert '400' in client.put(f'/v2/projects/{test_id}').status def test_update_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.put(f'/api/v2/projects/{test_id}', json={'project': {'name': 'S'}}).status + assert '404' in client.put(f'/v2/projects/{test_id}', json={'project': {'name': 'S'}}).status def test_update_project_not_authorized(client, mocker): @@ -63,7 +63,7 @@ def test_update_project_not_authorized(client, mocker): }] }) mocker.patch.object(DB, 'update', return_value={}) - assert '403' in client.put(f'/api/v2/projects/{test_id}', json={'project': {'name': 'S'}}).status + assert '403' in client.put(f'/v2/projects/{test_id}', json={'project': {'name': 'S'}}).status def test_update_project(client, mocker): @@ -78,13 +78,13 @@ def test_update_project(client, mocker): }) mocker.patch.object(DB, 'update', return_value={}) - res = client.put(f'/api/v2/projects/{test_id}', json={'project': {'name': 'S'}}) + res = client.put(f'/v2/projects/{test_id}', json={'project': {'name': 'S'}}) assert '200' in res.status def test_delete_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.delete(f'/api/v2/projects/{test_id}').status + assert '404' in client.delete(f'/v2/projects/{test_id}').status def test_delete_project_different_user(client, mocker): @@ -100,7 +100,7 @@ def test_delete_project_different_user(client, mocker): 'topologyIds': [] }) mocker.patch.object(DB, 'delete_one', return_value=None) - assert '403' in client.delete(f'/api/v2/projects/{test_id}').status + assert '403' in client.delete(f'/v2/projects/{test_id}').status def test_delete_project(client, mocker): @@ -118,5 +118,5 @@ def test_delete_project(client, mocker): }) mocker.patch.object(DB, 'update', return_value=None) mocker.patch.object(DB, 'delete_one', return_value={'googleId': 'test'}) - res = client.delete(f'/api/v2/projects/{test_id}') + res = client.delete(f'/v2/projects/{test_id}') assert '200' in res.status diff --git a/api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py b/api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py index 8ccebdad..71e88f00 100644 --- a/api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py +++ b/api/opendc/api/v2/projects/projectId/topologies/test_endpoint.py @@ -4,7 +4,7 @@ test_id = 24 * '1' def test_add_topology_missing_parameter(client): - assert '400' in client.post(f'/api/v2/projects/{test_id}/topologies').status + assert '400' in client.post(f'/v2/projects/{test_id}/topologies').status def test_add_topology(client, mocker): @@ -27,7 +27,7 @@ def test_add_topology(client, mocker): 'topologyIds': [] }) mocker.patch.object(DB, 'update', return_value={}) - res = client.post(f'/api/v2/projects/{test_id}/topologies', json={'topology': {'name': 'test project', 'rooms': []}}) + res = client.post(f'/v2/projects/{test_id}/topologies', json={'topology': {'name': 'test project', 'rooms': []}}) assert 'rooms' in res.json['content'] assert '200' in res.status @@ -43,7 +43,7 @@ def test_add_topology_not_authorized(client, mocker): 'authorizationLevel': 'VIEW' }] }) - assert '403' in client.post(f'/api/v2/projects/{test_id}/topologies', + assert '403' in client.post(f'/v2/projects/{test_id}/topologies', json={ 'topology': { 'name': 'test_topology', diff --git a/api/opendc/api/v2/projects/test_endpoint.py b/api/opendc/api/v2/projects/test_endpoint.py index cf02143c..9444b1e4 100644 --- a/api/opendc/api/v2/projects/test_endpoint.py +++ b/api/opendc/api/v2/projects/test_endpoint.py @@ -4,7 +4,7 @@ test_id = 24 * '1' def test_add_project_missing_parameter(client): - assert '400' in client.post('/api/v2/projects').status + assert '400' in client.post('/v2/projects').status def test_add_project(client, mocker): @@ -18,7 +18,7 @@ def test_add_project(client, mocker): 'topologyIds': [] }) mocker.patch.object(DB, 'update', return_value={}) - res = client.post('/api/v2/projects', json={'project': {'name': 'test project'}}) + res = client.post('/v2/projects', json={'project': {'name': 'test project'}}) assert 'datetimeCreated' in res.json['content'] assert 'datetimeLastEdited' in res.json['content'] assert 'topologyIds' in res.json['content'] diff --git a/api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py b/api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py index 386a9eea..cd4bcdf8 100644 --- a/api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py +++ b/api/opendc/api/v2/scenarios/scenarioId/test_endpoint.py @@ -6,7 +6,7 @@ test_id_2 = 24 * '2' def test_get_scenario_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get(f'/api/v2/scenarios/{test_id}').status + assert '404' in client.get(f'/v2/scenarios/{test_id}').status def test_get_scenario_no_authorizations(client, mocker): @@ -14,7 +14,7 @@ def test_get_scenario_no_authorizations(client, mocker): 'portfolioId': '1', 'authorizations': [] }) - res = client.get(f'/api/v2/scenarios/{test_id}') + res = client.get(f'/v2/scenarios/{test_id}') assert '403' in res.status @@ -30,7 +30,7 @@ def test_get_scenario_not_authorized(client, mocker): 'authorizationLevel': 'OWN' }] }) - res = client.get(f'/api/v2/scenarios/{test_id}') + res = client.get(f'/v2/scenarios/{test_id}') assert '403' in res.status @@ -46,17 +46,17 @@ def test_get_scenario(client, mocker): 'authorizationLevel': 'EDIT' }] }) - res = client.get(f'/api/v2/scenarios/{test_id}') + res = client.get(f'/v2/scenarios/{test_id}') assert '200' in res.status def test_update_scenario_missing_parameter(client): - assert '400' in client.put(f'/api/v2/scenarios/{test_id}').status + assert '400' in client.put(f'/v2/scenarios/{test_id}').status def test_update_scenario_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.put(f'/api/v2/scenarios/{test_id}', json={ + assert '404' in client.put(f'/v2/scenarios/{test_id}', json={ 'scenario': { 'name': 'test', } @@ -76,7 +76,7 @@ def test_update_scenario_not_authorized(client, mocker): }] }) mocker.patch.object(DB, 'update', return_value={}) - assert '403' in client.put(f'/api/v2/scenarios/{test_id}', json={ + assert '403' in client.put(f'/v2/scenarios/{test_id}', json={ 'scenario': { 'name': 'test', } @@ -101,7 +101,7 @@ def test_update_scenario(client, mocker): }) mocker.patch.object(DB, 'update', return_value={}) - res = client.put(f'/api/v2/scenarios/{test_id}', json={'scenario': { + res = client.put(f'/v2/scenarios/{test_id}', json={'scenario': { 'name': 'test', }}) assert '200' in res.status @@ -109,7 +109,7 @@ def test_update_scenario(client, mocker): def test_delete_project_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.delete(f'/api/v2/scenarios/{test_id}').status + assert '404' in client.delete(f'/v2/scenarios/{test_id}').status def test_delete_project_different_user(client, mocker): @@ -126,7 +126,7 @@ def test_delete_project_different_user(client, mocker): }] }) mocker.patch.object(DB, 'delete_one', return_value=None) - assert '403' in client.delete(f'/api/v2/scenarios/{test_id}').status + assert '403' in client.delete(f'/v2/scenarios/{test_id}').status def test_delete_project(client, mocker): @@ -145,5 +145,5 @@ def test_delete_project(client, mocker): }) mocker.patch.object(DB, 'delete_one', return_value={}) mocker.patch.object(DB, 'update', return_value=None) - res = client.delete(f'/api/v2/scenarios/{test_id}') + res = client.delete(f'/v2/scenarios/{test_id}') assert '200' in res.status diff --git a/api/opendc/api/v2/schedulers/test_endpoint.py b/api/opendc/api/v2/schedulers/test_endpoint.py index a0bd8758..4950ca4c 100644 --- a/api/opendc/api/v2/schedulers/test_endpoint.py +++ b/api/opendc/api/v2/schedulers/test_endpoint.py @@ -1,2 +1,2 @@ def test_get_schedulers(client): - assert '200' in client.get('/api/v2/schedulers').status + assert '200' in client.get('/v2/schedulers').status diff --git a/api/opendc/api/v2/topologies/topologyId/test_endpoint.py b/api/opendc/api/v2/topologies/topologyId/test_endpoint.py index 76243ad6..4da0bc64 100644 --- a/api/opendc/api/v2/topologies/topologyId/test_endpoint.py +++ b/api/opendc/api/v2/topologies/topologyId/test_endpoint.py @@ -15,13 +15,13 @@ def test_get_topology(client, mocker): 'authorizationLevel': 'EDIT' }] }) - res = client.get(f'/api/v2/topologies/{test_id}') + res = client.get(f'/v2/topologies/{test_id}') assert '200' in res.status def test_get_topology_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get('/api/v2/topologies/1').status + assert '404' in client.get('/v2/topologies/1').status def test_get_topology_not_authorized(client, mocker): @@ -35,23 +35,23 @@ def test_get_topology_not_authorized(client, mocker): 'authorizationLevel': 'OWN' }] }) - res = client.get(f'/api/v2/topologies/{test_id}') + res = client.get(f'/v2/topologies/{test_id}') assert '403' in res.status def test_get_topology_no_authorizations(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'projectId': test_id, 'authorizations': []}) - res = client.get(f'/api/v2/topologies/{test_id}') + res = client.get(f'/v2/topologies/{test_id}') assert '403' in res.status def test_update_topology_missing_parameter(client): - assert '400' in client.put(f'/api/v2/topologies/{test_id}').status + assert '400' in client.put(f'/v2/topologies/{test_id}').status def test_update_topology_non_existent(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.put(f'/api/v2/topologies/{test_id}', json={'topology': {'name': 'test_topology', 'rooms': {}}}).status + assert '404' in client.put(f'/v2/topologies/{test_id}', json={'topology': {'name': 'test_topology', 'rooms': {}}}).status def test_update_topology_not_authorized(client, mocker): @@ -66,7 +66,7 @@ def test_update_topology_not_authorized(client, mocker): }] }) mocker.patch.object(DB, 'update', return_value={}) - assert '403' in client.put(f'/api/v2/topologies/{test_id}', json={ + assert '403' in client.put(f'/v2/topologies/{test_id}', json={ 'topology': { 'name': 'updated_topology', 'rooms': {} @@ -87,7 +87,7 @@ def test_update_topology(client, mocker): }) mocker.patch.object(DB, 'update', return_value={}) - assert '200' in client.put(f'/api/v2/topologies/{test_id}', json={ + assert '200' in client.put(f'/v2/topologies/{test_id}', json={ 'topology': { 'name': 'updated_topology', 'rooms': {} @@ -110,10 +110,10 @@ def test_delete_topology(client, mocker): }) mocker.patch.object(DB, 'delete_one', return_value={}) mocker.patch.object(DB, 'update', return_value=None) - res = client.delete(f'/api/v2/topologies/{test_id}') + res = client.delete(f'/v2/topologies/{test_id}') assert '200' in res.status def test_delete_nonexistent_topology(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.delete(f'/api/v2/topologies/{test_id}').status + assert '404' in client.delete(f'/v2/topologies/{test_id}').status diff --git a/api/opendc/api/v2/traces/test_endpoint.py b/api/opendc/api/v2/traces/test_endpoint.py index 9f806085..36846bd9 100644 --- a/api/opendc/api/v2/traces/test_endpoint.py +++ b/api/opendc/api/v2/traces/test_endpoint.py @@ -3,4 +3,4 @@ from opendc.util.database import DB def test_get_traces(client, mocker): mocker.patch.object(DB, 'fetch_all', return_value=[]) - assert '200' in client.get('/api/v2/traces').status + assert '200' in client.get('/v2/traces').status diff --git a/api/opendc/api/v2/traces/traceId/test_endpoint.py b/api/opendc/api/v2/traces/traceId/test_endpoint.py index 144f02bb..0c51538b 100644 --- a/api/opendc/api/v2/traces/traceId/test_endpoint.py +++ b/api/opendc/api/v2/traces/traceId/test_endpoint.py @@ -5,11 +5,11 @@ test_id = 24 * '1' def test_get_trace_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get(f'/api/v2/traces/{test_id}').status + assert '404' in client.get(f'/v2/traces/{test_id}').status def test_get_trace(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'name': 'test trace'}) - res = client.get(f'/api/v2/traces/{test_id}') + res = client.get(f'/v2/traces/{test_id}') assert 'name' in res.json['content'] assert '200' in res.status diff --git a/api/opendc/api/v2/users/test_endpoint.py b/api/opendc/api/v2/users/test_endpoint.py index d60429b3..13b63b20 100644 --- a/api/opendc/api/v2/users/test_endpoint.py +++ b/api/opendc/api/v2/users/test_endpoint.py @@ -2,33 +2,33 @@ from opendc.util.database import DB def test_get_user_by_email_missing_parameter(client): - assert '400' in client.get('/api/v2/users').status + assert '400' in client.get('/v2/users').status def test_get_user_by_email_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get('/api/v2/users?email=test@test.com').status + assert '404' in client.get('/v2/users?email=test@test.com').status def test_get_user_by_email(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'email': 'test@test.com'}) - res = client.get('/api/v2/users?email=test@test.com') + res = client.get('/v2/users?email=test@test.com') assert 'email' in res.json['content'] assert '200' in res.status def test_add_user_missing_parameter(client): - assert '400' in client.post('/api/v2/users').status + assert '400' in client.post('/v2/users').status def test_add_user_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'email': 'test@test.com'}) - assert '409' in client.post('/api/v2/users', json={'user': {'email': 'test@test.com'}}).status + assert '409' in client.post('/v2/users', json={'user': {'email': 'test@test.com'}}).status def test_add_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) mocker.patch.object(DB, 'insert', return_value={'email': 'test@test.com'}) - res = client.post('/api/v2/users', json={'user': {'email': 'test@test.com'}}) + res = client.post('/v2/users', json={'user': {'email': 'test@test.com'}}) assert 'email' in res.json['content'] assert '200' in res.status diff --git a/api/opendc/api/v2/users/userId/test_endpoint.py b/api/opendc/api/v2/users/userId/test_endpoint.py index 89549f33..4085642f 100644 --- a/api/opendc/api/v2/users/userId/test_endpoint.py +++ b/api/opendc/api/v2/users/userId/test_endpoint.py @@ -5,52 +5,52 @@ test_id = 24 * '1' def test_get_user_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.get(f'/api/v2/users/{test_id}').status + assert '404' in client.get(f'/v2/users/{test_id}').status def test_get_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'email': 'test@test.com'}) - res = client.get(f'/api/v2/users/{test_id}') + res = client.get(f'/v2/users/{test_id}') assert 'email' in res.json['content'] assert '200' in res.status def test_update_user_missing_parameter(client): - assert '400' in client.put(f'/api/v2/users/{test_id}').status + assert '400' in client.put(f'/v2/users/{test_id}').status def test_update_user_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.put(f'/api/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}).status + assert '404' in client.put(f'/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}).status def test_update_user_different_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'other_test'}) - assert '403' in client.put(f'/api/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}).status + assert '403' in client.put(f'/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}).status def test_update_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'test'}) mocker.patch.object(DB, 'update', return_value={'givenName': 'A', 'familyName': 'B'}) - res = client.put(f'/api/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}) + res = client.put(f'/v2/users/{test_id}', json={'user': {'givenName': 'A', 'familyName': 'B'}}) assert 'givenName' in res.json['content'] assert '200' in res.status def test_delete_user_non_existing(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value=None) - assert '404' in client.delete(f'/api/v2/users/{test_id}').status + assert '404' in client.delete(f'/v2/users/{test_id}').status def test_delete_user_different_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'other_test'}) - assert '403' in client.delete(f'/api/v2/users/{test_id}').status + assert '403' in client.delete(f'/v2/users/{test_id}').status def test_delete_user(client, mocker): mocker.patch.object(DB, 'fetch_one', return_value={'_id': test_id, 'googleId': 'test', 'authorizations': []}) mocker.patch.object(DB, 'delete_one', return_value={'googleId': 'test'}) - res = client.delete(f'/api/v2/users/{test_id}', ) + res = client.delete(f'/v2/users/{test_id}', ) assert 'googleId' in res.json['content'] assert '200' in res.status diff --git a/api/pytest.ini b/api/pytest.ini index 775a8ff4..8c28be16 100644 --- a/api/pytest.ini +++ b/api/pytest.ini @@ -2,4 +2,3 @@ env = OPENDC_FLASK_TESTING=True OPENDC_FLASK_SECRET=Secret - OPENDC_SERVER_BASE_URL=localhost diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 00000000..8c822c98 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,31 @@ +version: "3.8" + +# Docker Compose overrides for development environments +services: + frontend: + build: + args: + OPENDC_API_BASE_URL: http://localhost:8081 + ports: + - "8080:80" + + api: + ports: + - "8081:8081" + + mongo: + ports: + - "27017:27017" + + mongo-express: + image: mongo-express + restart: on-failure + networks: + - backend + depends_on: + - mongo + ports: + - "8082:8081" + environment: + ME_CONFIG_MONGODB_ADMINUSERNAME: "${MONGO_INITDB_ROOT_USERNAME}" + ME_CONFIG_MONGODB_ADMINPASSWORD: "${MONGO_INITDB_ROOT_PASSWORD}" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 00000000..63166967 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,14 @@ +version: "3.8" + +# Docker Compose overrides for production environments +services: + frontend: + build: + args: + OPENDC_API_BASE_URL: ${OPENDC_API_BASE_URL} + ports: + - "8080:80" + + api: + ports: + - "8081:8081" diff --git a/docker-compose.yml b/docker-compose.yml index c3e62317..4d62b7cd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,23 +4,16 @@ services: build: context: ./frontend args: - - REACT_APP_OAUTH_CLIENT_ID=${OPENDC_OAUTH_CLIENT_ID} + OPENDC_OAUTH_CLIENT_ID: ${OPENDC_OAUTH_CLIENT_ID} image: frontend restart: on-failure networks: - backend - depends_on: - - api - ports: - - "8081:80" api: build: ./api image: api restart: on-failure - # Comment out these 2 lines for deployment - ports: - - "8082:8081" networks: - backend depends_on: @@ -35,8 +28,6 @@ services: - OPENDC_DB_HOST=mongo - OPENDC_FLASK_SECRET - OPENDC_OAUTH_CLIENT_ID - - OPENDC_ROOT_DIR - - OPENDC_SERVER_BASE_URL simulator: build: ./simulator @@ -73,25 +64,9 @@ services: - OPENDC_DB_PASSWORD networks: - backend - # Comment out for public deployment - ports: - - "27017:27017" volumes: - mongo-volume:/data/db - mongo-express: - image: mongo-express - restart: on-failure - networks: - - backend - depends_on: - - mongo - ports: - - "8083:8081" - environment: - ME_CONFIG_MONGODB_ADMINUSERNAME: "${MONGO_INITDB_ROOT_USERNAME}" - ME_CONFIG_MONGODB_ADMINPASSWORD: "${MONGO_INITDB_ROOT_PASSWORD}" - volumes: mongo-volume: results-volume: diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1 @@ +node_modules diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 36e3c20b..113b09c9 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,7 +1,8 @@ FROM node:14 MAINTAINER OpenDC Maintainers <opendc@atlarge-research.com> -ARG REACT_APP_OAUTH_CLIENT_ID +ARG OPENDC_OAUTH_CLIENT_ID +ARG OPENDC_API_BASE_URL # Copy OpenDC directory COPY ./ /opendc @@ -10,7 +11,8 @@ COPY ./ /opendc RUN cd /opendc/ \ && rm -rf ./build \ && yarn \ - && export REACT_APP_OAUTH_CLIENT_ID=$REACT_APP_OAUTH_CLIENT_ID \ + && export REACT_APP_OAUTH_CLIENT_ID=$OPENDC_OAUTH_CLIENT_ID \ + && export REACT_APP_API_BASE_URL=$OPENDC_API_BASE_URL \ && yarn build # Setup nginx to serve the frontend diff --git a/frontend/nginx.conf b/frontend/nginx.conf index ed7e5cfe..1b4e3a73 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -8,23 +8,6 @@ server { try_files $uri $uri/ /index.html; } - location /socket.io { - proxy_http_version 1.1; - - proxy_buffering off; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_pass http://api:8081/socket.io; - } - - location /tokensignin { - proxy_pass http://api:8081/tokensignin; - } - - location /api { - proxy_pass http://api:8081/api; - } - error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; diff --git a/frontend/public/img/screenshot-construction.png b/frontend/public/img/screenshot-construction.png Binary files differnew file mode 100644 index 00000000..223e8d48 --- /dev/null +++ b/frontend/public/img/screenshot-construction.png diff --git a/frontend/public/img/screenshot-simulation-zoom.png b/frontend/public/img/screenshot-simulation-zoom.png Binary files differnew file mode 100644 index 00000000..d7744926 --- /dev/null +++ b/frontend/public/img/screenshot-simulation-zoom.png diff --git a/frontend/src/api/routes/token-signin.js b/frontend/src/api/routes/token-signin.js index 7553d043..d6cff570 100644 --- a/frontend/src/api/routes/token-signin.js +++ b/frontend/src/api/routes/token-signin.js @@ -1,5 +1,10 @@ export function performTokenSignIn(token) { - return new Promise((resolve) => { - window['jQuery'].post('/tokensignin', { idtoken: token }, (data) => resolve(data)) - }) + const apiUrl = process.env.REACT_APP_API_BASE_URL || '' + + return fetch(`${apiUrl}/tokensignin`, { + method: 'POST', + body: new URLSearchParams({ + idtoken: token, + }), + }).then((res) => res.json()) } diff --git a/frontend/src/api/socket.js b/frontend/src/api/socket.js index 96034021..1c432167 100644 --- a/frontend/src/api/socket.js +++ b/frontend/src/api/socket.js @@ -6,9 +6,11 @@ let requestIdCounter = 0 const callbacks = {} export function setupSocketConnection(onConnect) { - const apiUrl = process.env.REACT_APP_API_URL || window.location.hostname + ':' + window.location.port + const apiUrl = + process.env.REACT_APP_API_BASE_URL || + `${window.location.protocol}//${window.location.hostname}:${window.location.port}` - socket = io.connect(window.location.protocol + '//' + apiUrl) + socket = io.connect(apiUrl) socket.on('connect', onConnect) socket.on('response', onSocketResponse) } diff --git a/frontend/src/components/home/ModelingSection.js b/frontend/src/components/home/ModelingSection.js index 60d372f2..643dca65 100644 --- a/frontend/src/components/home/ModelingSection.js +++ b/frontend/src/components/home/ModelingSection.js @@ -5,7 +5,7 @@ const ModelingSection = () => ( <ScreenshotSection name="modeling" title="Datacenter Modeling" - imageUrl="https://github.com/atlarge-research/opendc/raw/master/images/opendc-frontend-construction.PNG" + imageUrl="/img/screenshot-construction.png" caption="Building a datacenter in OpenDC" imageIsRight={true} > diff --git a/frontend/src/components/home/SimulationSection.js b/frontend/src/components/home/SimulationSection.js index 9852cbb8..e7a02068 100644 --- a/frontend/src/components/home/SimulationSection.js +++ b/frontend/src/components/home/SimulationSection.js @@ -5,7 +5,7 @@ const ModelingSection = () => ( <ScreenshotSection name="simulation" title="Datacenter Simulation" - imageUrl="https://github.com/atlarge-research/opendc/raw/master/images/opendc-frontend-simulation-zoom.PNG" + imageUrl="/img/screenshot-simulation-zoom.png" caption="Running an experiment in OpenDC" imageIsRight={false} > |
