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

Testing done #138

Merged
merged 4 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
Routes and sub-resources for the /docker resource
"""
import json
from flask import Blueprint, jsonify, request

import csle_common.constants.constants as constants
from csle_cluster.cluster_manager.cluster_controller import ClusterController
from csle_common.metastore.metastore_facade import MetastoreFacade
from flask import Blueprint, jsonify, request

import csle_rest_api.constants.constants as api_constants
import csle_rest_api.util.rest_api_util as rest_api_util
from csle_common.metastore.metastore_facade import MetastoreFacade
from csle_cluster.cluster_manager.cluster_controller import ClusterController

# Creates a blueprint "sub application" of the main REST app
docker_bp = Blueprint(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE, __name__,
Expand All @@ -25,24 +27,25 @@ def docker():
authorized = rest_api_util.check_if_user_is_authorized(request=request, requires_admin=requires_admin)
if authorized is not None:
return authorized

json_data = json.loads(request.data)
if api_constants.MGMT_WEBAPP.IP_PROPERTY not in json_data:
return jsonify({}), constants.HTTPS.BAD_REQUEST_STATUS_CODE
ip = json_data[api_constants.MGMT_WEBAPP.IP_PROPERTY]
if request.method == api_constants.MGMT_WEBAPP.HTTP_REST_POST:
json_data = json.loads(request.data)
if api_constants.MGMT_WEBAPP.IP_PROPERTY not in json_data:
return jsonify({}), constants.HTTPS.BAD_REQUEST_STATUS_CODE
ip = json_data[api_constants.MGMT_WEBAPP.IP_PROPERTY]

config = MetastoreFacade.get_config(id=1)
cluster_statuses = []
for node in config.cluster_config.cluster_nodes:
node_status = ClusterController.get_node_status(ip=node.ip, port=constants.GRPC_SERVERS.CLUSTER_MANAGER_PORT)
if node.ip == ip:
if request.method == api_constants.MGMT_WEBAPP.HTTP_REST_POST:
if node_status.dockerRunning:
if request.method == api_constants.MGMT_WEBAPP.HTTP_REST_POST:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jag tror inte detta är korrekt. Säg att jag har två cluster nodes med id 1 och 2. Antag att jag gör ett POST request med id=2. Då kommer jag få en BAD REQUEST pga att 1 != 2 (Rätta mig om jag har fel).

Jag tror du måste lägga in en Boolean variabel innan loopen börjar, ex ip_found=False, dvs innan for node in config.cluster_config.cluster_nodes: sedan om du får en match på IP inuti loopen då sätter du ip_found = True. Sedan har du en if-statement utanför loopen:

if not ip_found: return BAD_REQUEST`

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: På if-statement utanför loopen måste du också kolla att det är en POST. i.e. if not ip_found and method==POST: return BAD REQUEST

Copy link
Contributor Author

@nforsg nforsg Jul 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oright! Ska först göra klart get-metoden i experiments, sen fixar jag detta

Copy link
Contributor Author

@nforsg nforsg Jul 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jag gjorde ett förslag på lösning med ip_found. Vet inte om du ville att jag skulle byta plats på POST-statement, men tidigare då ip har påkallats före POST har vi haft en bugg p.g.a att GET inte har någon ip och då fås "referenced before assignment" för samtliga GET-requests.

if node.ip == ip:
# what about node.ip != ip?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Du kan lägga in en boolean variable och kolla om ip inte matchar någon node.ip kan du returnera return jsonify({"reason": f"node with ip {ip} does not exist."}), constants.HTTPS.BAD_REQUEST_STATUS_CODE

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixat, tror jag

if node_status.dockerEngineRunning:
ClusterController.stop_docker_engine(ip=node.ip, port=constants.GRPC_SERVERS.CLUSTER_MANAGER_PORT)
node_status.dockerRunning = False
node_status.dockerEngineRunning = False
else:
ClusterController.start_docker_engine(ip=node.ip, port=constants.GRPC_SERVERS.CLUSTER_MANAGER_PORT)
node_status.dockerRunning = True
node_status.dockerEngineRunning = True
cluster_status_dict = {
api_constants.MGMT_WEBAPP.CADVISOR_RUNNING_PROPERTY: node_status.cAdvisorRunning,
api_constants.MGMT_WEBAPP.GRAFANA_RUNNING_PROPERTY: node_status.grafanaRunning,
Expand Down
311 changes: 311 additions & 0 deletions simulation-system/libs/csle-rest-api/tests/test_resources_docker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
import json
import logging
from typing import List

import csle_common.constants.constants as constants
import pytest
import pytest_mock
from csle_cluster.cluster_manager.cluster_manager_pb2 import (
NodeStatusDTO,
ServiceStatusDTO,
)
from csle_common.dao.emulation_config.config import Config

import csle_rest_api.constants.constants as api_constants
from csle_rest_api.rest_api import create_app


class TestResourcesDockerStatusSuite:
"""
Test suite for /cluster_status url
"""

pytest.logger = logging.getLogger("resources_docker_tests")

@pytest.fixture
def flask_app(self):
"""
Gets the Flask app

:return: the flask app fixture representing the webserver
"""
return create_app(static_folder="../../../../../management-system/csle-mgmt-webapp/build")

@pytest.fixture
def config(self, mocker, example_config: Config):
"""
Pytest fixture for mocking the get_config function

:param mocker: the pytest mocker object
:param example config: example config from the
conftest.py file
:return: the pytest fixture for the get_config functione
"""
def get_config(id: int) -> Config:
conf = example_config
return conf

get_config_mocker = mocker.MagicMock(
side_effect=get_config)
return get_config_mocker

@pytest.fixture
def stop_docker(self, mocker: pytest_mock.MockFixture):
"""
Pytest fixture for mocking the stop_docker_engine function
:param mocker: the pytest mocker object
:return: the pytest fixture for the stop_docker_engine function
"""
def stop_docker_engine(ip: str, port: int) -> ServiceStatusDTO:
status = ServiceStatusDTO(running=False)
return status
stop_docker_engine_mocker = mocker.MagicMock(
side_effect=stop_docker_engine)
return stop_docker_engine_mocker

@pytest.fixture
def start_docker(self, mocker: pytest_mock.MockFixture):
"""
Pytest fixture for mocking the stop_docker_engine function
:param mocker: the pytest mocker object
:return: the pytest fixture for the stop_docker_engine function
"""
def start_docker_engine(ip: str, port: int) -> ServiceStatusDTO:
status = ServiceStatusDTO(running=True)
return status
start_docker_engine_mocker = mocker.MagicMock(
side_effect=start_docker_engine)
return start_docker_engine_mocker

@pytest.fixture
def node_status_docker_running(self, mocker: pytest_mock.MockFixture,
example_node_status: NodeStatusDTO):
"""
Pytest fixture for mocking the get_node_status function when
the Docker engine is running

:param mocker: the pytest mocker object
:param example_node_status: example config from the
conftest.py file
:return: the pytest fixture for the get_node_status function
"""
def get_node_status(ip: str, port: int) -> NodeStatusDTO:
node_status = example_node_status
node_status.dockerEngineRunning = True
return node_status
get_node_status_mock = mocker.MagicMock(
side_effect=get_node_status)
return get_node_status_mock

@pytest.fixture
def node_status_docker_not_running(self, mocker: pytest_mock.MockFixture,
example_node_status: NodeStatusDTO):
"""
Pytest fixture for mocking the get_node_status function when
the Docker engine is down

:param mocker: the pytest mocker object
:param example_node_status: example config from the
conftest.py file
:return: the pytest fixture for the get_node_status function
"""
def get_node_status(ip: str, port: int) -> NodeStatusDTO:
node_status = example_node_status
node_status.dockerEngineRunning = False
return node_status
get_node_status_mock = mocker.MagicMock(
side_effect=get_node_status)
return get_node_status_mock

@staticmethod
def cluster_node_status(example_config: Config,
example_node_status: NodeStatusDTO) -> List[dict]:
"""
Staticmethod that reurns an example cluster node status, that is
to be tested against the mocking ofthe API
:param example_config: an example Config class
:param exmaple_node_status: an example node status class
:return: a list of a dict containing an example cluster node status
"""
config = example_config
cluster_statuses = []
for node in config.cluster_config.cluster_nodes:
node_status = example_node_status
cluster_status_dict = {
api_constants.MGMT_WEBAPP.CADVISOR_RUNNING_PROPERTY: node_status.cAdvisorRunning,
api_constants.MGMT_WEBAPP.GRAFANA_RUNNING_PROPERTY: node_status.grafanaRunning,
api_constants.MGMT_WEBAPP.POSTGRESQL_RUNNING_PROPERTY: node_status.postgreSQLRunning,
api_constants.MGMT_WEBAPP.NODE_EXPORTER_RUNNING_PROPERTY: node_status.nodeExporterRunning,
api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY: node_status.dockerEngineRunning,
api_constants.MGMT_WEBAPP.NGINX_RUNNING_PROPERTY: node_status.nginxRunning,
api_constants.MGMT_WEBAPP.FLASK_RUNNING_PROPERTY: node_status.flaskRunning,
api_constants.MGMT_WEBAPP.PROMETHEUS_RUNNING_PROPERTY: node_status.prometheusRunning,
api_constants.MGMT_WEBAPP.PGADMIN_RUNNING_PROPERTY: node_status.pgAdminRunning,
api_constants.MGMT_WEBAPP.CADVISOR_URL_PROPERTY:
f"http://{node.ip}:{constants.COMMANDS.CADVISOR_PORT}/",
api_constants.MGMT_WEBAPP.GRAFANA_URL_PROPERTY: f"http://{node.ip}:{constants.COMMANDS.GRAFANA_PORT}/",
api_constants.MGMT_WEBAPP.NODE_EXPORTER_URL_PROPERTY: f"http://{node.ip}:"
f"{constants.COMMANDS.NODE_EXPORTER_PORT}/",
api_constants.MGMT_WEBAPP.FLASK_URL_PROPERTY: f"http://{node.ip}:{constants.COMMANDS.FLASK_PORT}/",
api_constants.MGMT_WEBAPP.PROMETHEUS_URL_PROPERTY: f"http://{node.ip}:"
f"{constants.COMMANDS.PROMETHEUS_PORT}/",
api_constants.MGMT_WEBAPP.PGADMIN_URL_PROPERTY: f"http://{node.ip}:{constants.COMMANDS.PGADMIN_PORT}/",
api_constants.MGMT_WEBAPP.CADVISOR_PORT_PROPERTY: constants.COMMANDS.CADVISOR_PORT,
api_constants.MGMT_WEBAPP.GRAFANA_PORT_PROPERTY: constants.COMMANDS.GRAFANA_PORT,
api_constants.MGMT_WEBAPP.NODE_EXPORTER_PORT_PROPERTY: constants.COMMANDS.NODE_EXPORTER_PORT,
api_constants.MGMT_WEBAPP.FLASK_PORT_PROPERTY: constants.COMMANDS.FLASK_PORT,
api_constants.MGMT_WEBAPP.PROMETHEUS_PORT_PROPERTY: constants.COMMANDS.PROMETHEUS_PORT,
api_constants.MGMT_WEBAPP.PGADMIN_PORT_PROPERTY: constants.COMMANDS.PGADMIN_PORT,
api_constants.MGMT_WEBAPP.IP_PROPERTY: node.ip,
api_constants.MGMT_WEBAPP.CPUS_PROPERTY: node.cpus,
api_constants.MGMT_WEBAPP.GPUS_PROPERTY: node.gpus,
api_constants.MGMT_WEBAPP.RAM_PROPERTY: node.RAM,
api_constants.MGMT_WEBAPP.LEADER_PROPERTY: node.leader
}
cluster_statuses.append(cluster_status_dict)
return cluster_statuses

def test_docker_get(self, flask_app, mocker,
config, node_status_docker_running,
not_logged_in, logged_in,
logged_in_as_admin, example_config,
example_node_status):
"""
Tests the GET HTTPS method for the /docker url

:param flask_app: the pytest flask app for making requests
:param mocker: the pytest mocker object
:param logged_in_as_admin: the logged_in_as_admin fixture
:param logged_in: the logged_in fixture
:param not_logged_in: the not_logged_in fixture
:param get_: the config fixture
:param node_status: the node_status fixture
:return: None
"""
test_ns = TestResourcesDockerStatusSuite.cluster_node_status(example_config,
example_node_status)
test_ns_dict = test_ns[0]
mocker.patch("csle_rest_api.util.rest_api_util.check_if_user_is_authorized",
side_effect=not_logged_in)
mocker.patch("csle_common.metastore.metastore_facade.MetastoreFacade.get_config",
side_effect=config)
mocker.patch("csle_cluster.cluster_manager.cluster_controller.ClusterController.get_node_status",
side_effect=node_status_docker_running)
response = flask_app.test_client().get(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE)
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
assert response.status_code == constants.HTTPS.UNAUTHORIZED_STATUS_CODE
assert response_data_list == {}
mocker.patch("csle_rest_api.util.rest_api_util.check_if_user_is_authorized",
side_effect=logged_in)
response = flask_app.test_client().get(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE)
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
assert response.status_code == constants.HTTPS.OK_STATUS_CODE
response_data_dict = response_data_list[0]
for k in response_data_dict:
assert response_data_dict[k] == test_ns_dict[k]
mocker.patch("csle_rest_api.util.rest_api_util.check_if_user_is_authorized",
side_effect=logged_in_as_admin)
response = flask_app.test_client().get(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE)
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
assert response.status_code == constants.HTTPS.OK_STATUS_CODE
response_data_dict = response_data_list[0]
for k in response_data_dict:
assert response_data_dict[k] == test_ns_dict[k]

def test_docker_post(self, flask_app, mocker,
node_status_docker_running,
node_status_docker_not_running,
config, not_logged_in,
logged_in, logged_in_as_admin,
example_config, example_node_status,
stop_docker, start_docker):
"""
Tests the POST HTTPS method for the /docker url

:param flask_app: the pytest flask app for making requests
:param mocker: the pytest mocker object
:param logged_in_as_admin: the logged_in_as_admin fixture
:param logged_in: the logged_in fixture
:param not_logged_in: the not_logged_in fixture
:param get_: the config fixture
:param node_status: the node_status fixture
:return: None
"""
test_ns = TestResourcesDockerStatusSuite.cluster_node_status(example_config,
example_node_status)
test_ns_dict = test_ns[0]

mocker.patch("csle_rest_api.util.rest_api_util.check_if_user_is_authorized",
side_effect=not_logged_in)
mocker.patch("csle_common.metastore.metastore_facade.MetastoreFacade.get_config",
side_effect=config)
mocker.patch("csle_cluster.cluster_manager.cluster_controller.ClusterController.get_node_status",
side_effect=node_status_docker_running)
mocker.patch("csle_cluster.cluster_manager.cluster_controller.ClusterController.stop_docker_engine",
side_effect=stop_docker)
mocker.patch("csle_cluster.cluster_manager.cluster_controller.ClusterController.start_docker_engine",
side_effect=start_docker)
response = flask_app.test_client().post(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE,
data=json.dumps({}))
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
assert response.status_code == constants.HTTPS.UNAUTHORIZED_STATUS_CODE
assert response_data_list == {}
mocker.patch("csle_rest_api.util.rest_api_util.check_if_user_is_authorized",
side_effect=logged_in)
response = flask_app.test_client().post(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE,
data=json.dumps({}))
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
mocker.patch("csle_rest_api.util.rest_api_util.check_if_user_is_authorized",
side_effect=logged_in_as_admin)
response = flask_app.test_client().post(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE,
data=json.dumps({}))
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
assert response_data_list == {}
assert response.status_code == \
constants.HTTPS.BAD_REQUEST_STATUS_CODE
mocker.patch("csle_rest_api.util.rest_api_util.check_if_user_is_authorized",
side_effect=logged_in_as_admin)
config = example_config
config_cluster_dict = config.cluster_config.to_dict()['cluster_nodes'][0]
response = flask_app.test_client().post(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE,
data=json.dumps(config_cluster_dict))
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
assert response.status_code == constants.HTTPS.OK_STATUS_CODE
response_data_dict = response_data_list[0]
for k in response_data_dict:
if k == api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY:
continue
else:
assert response_data_dict[k] == test_ns_dict[k]
assert response_data_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY] \
is False
assert test_ns_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY] \
is True
assert response_data_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY] != \
test_ns_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY]
mocker.patch("csle_cluster.cluster_manager.cluster_controller.ClusterController.get_node_status",
side_effect=node_status_docker_not_running)
response = flask_app.test_client().post(api_constants.MGMT_WEBAPP.DOCKER_RESOURCE,
data=json.dumps(config_cluster_dict))
response_data = response.data.decode('utf-8')
response_data_list = json.loads(response_data)
assert response.status_code == constants.HTTPS.OK_STATUS_CODE
response_data_dict = response_data_list[0]
for k in response_data_dict:
if k == api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY:
continue
else:
assert response_data_dict[k] == test_ns_dict[k]
assert response_data_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY] \
is True
assert test_ns_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY] \
is True
assert response_data_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY] == \
test_ns_dict[api_constants.MGMT_WEBAPP.DOCKER_ENGINE_RUNNING_PROPERTY]