diff --git a/fabric_cf/actor/core/apis/abc_actor_management_object.py b/fabric_cf/actor/core/apis/abc_actor_management_object.py index 96de16b5..2c267445 100644 --- a/fabric_cf/actor/core/apis/abc_actor_management_object.py +++ b/fabric_cf/actor/core/apis/abc_actor_management_object.py @@ -276,6 +276,48 @@ def get_slices(self, *, slice_id: ID, caller: AuthToken, slice_name: str = None, @return returns list of slices """ + @abstractmethod + def increment_metrics(self, *, project_id: str, oidc_sub: str, slice_count: int = 1) -> bool: + """ + Add or update metrics + + @param project_id project id + @param oidc_sub oidc sub + @param slice_count slice_count + + @return true or false + + @throws Exception in case of error + """ + + @abstractmethod + def get_metrics(self, *, project_id: str, oidc_sub: str, excluded_projects: List[str] = None) -> list: + """ + Get metrics + + @param project_id project id + @param oidc_sub oidc sub + @param excluded_projects excluded_projects + + @return list of metric information + + @throws Exception in case of error + """ + + def get_slice_count(self, *, caller: AuthToken, email: str = None, states: List[int] = None, + project: str = None, user_id: str = None, excluded_projects: List[str] = None) -> int: + """ + Obtains Slice count matching the filter criteria. + + @param email email + @param project project id + @param states slice states + @param caller caller + @param user_id user_id + @param excluded_projects excluded_projects + @return returns number of slices + """ + def remove_slice(self, *, slice_id: ID, caller: AuthToken) -> ResultAvro: """ Removes the specified slice diff --git a/fabric_cf/actor/core/apis/abc_database.py b/fabric_cf/actor/core/apis/abc_database.py index 99c81113..b0451540 100644 --- a/fabric_cf/actor/core/apis/abc_database.py +++ b/fabric_cf/actor/core/apis/abc_database.py @@ -217,6 +217,50 @@ def get_slices(self, *, slice_id: ID = None, slice_name: str = None, project_id: @throws Exception in case of error """ + @abstractmethod + def get_slice_count(self, *, project_id: str = None, email: str = None, states: list[int] = None, + oidc_sub: str = None, slc_type: List[SliceTypes] = None, + excluded_projects: List[str] = None) -> int: + """ + Retrieves the slices count. + + @param project_id project id + @param email email + @param states states + @param oidc_sub oidc sub + @param slc_type slice type + @param excluded_projects excluded_projects + + @return number of slices matching the filter criteria + + @throws Exception in case of error + """ + + @abstractmethod + def increment_metrics(self, *, project_id: str, oidc_sub: str, slice_count: int = 1) -> bool: + """ + Add or Update Metrics + + @param project_id project id + @param oidc_sub oidc sub + @param slice_count slice_count + + @return true or false + + @throws Exception in case of error + """ + + @abstractmethod + def get_metrics(self, *, project_id: str, oidc_sub: str, excluded_projects: List[str] = None) -> list: + """ + Get Metrics + @param project_id: project id + @param oidc_sub: user id + @param excluded_projects: list of project ids to exclude + + @return list of metrics + """ + @abstractmethod def initialize(self): """ diff --git a/fabric_cf/actor/core/apis/abc_mgmt_actor.py b/fabric_cf/actor/core/apis/abc_mgmt_actor.py index cebc73a3..33b7012b 100644 --- a/fabric_cf/actor/core/apis/abc_mgmt_actor.py +++ b/fabric_cf/actor/core/apis/abc_mgmt_actor.py @@ -63,6 +63,47 @@ def get_slices(self, *, slice_id: ID = None, slice_name: str = None, email: str @return returns list of slices """ + def increment_metrics(self, *, project_id: str, oidc_sub: str, slice_count: int = 1) -> bool: + """ + Add or update metrics + + @param project_id project id + @param oidc_sub oidc sub + @param slice_count slice_count + + @return true or false + + @throws Exception in case of error + """ + raise NotImplementedError + + def get_metrics(self, *, project_id: str, oidc_sub: str, excluded_projects: List[str] = None) -> list: + """ + Get metrics + + @param project_id project id + @param oidc_sub oidc sub + @param excluded_projects excluded_projects + + @return list of metric information + + @throws Exception in case of error + """ + raise NotImplementedError + + def get_slice_count(self, *, email: str = None, project: str = None, states: List[int] = None, + user_id: str = None, excluded_projects: List[str] = None) -> int: + """ + Obtains slice count. + @param email email + @param project project id + @param states slice states + @param user_id user_id + @param excluded_projects excluded_projects + @return returns list of slices + """ + raise NotImplementedError + @abstractmethod def add_slice(self, *, slice_obj: SliceAvro) -> ID: """ diff --git a/fabric_cf/actor/core/common/constants.py b/fabric_cf/actor/core/common/constants.py index 7ee085ff..a1735b4c 100644 --- a/fabric_cf/actor/core/common/constants.py +++ b/fabric_cf/actor/core/common/constants.py @@ -199,6 +199,7 @@ class Constants: STATE_FILE_LOCATION = '/tmp/fabric_actor.tmp' MAINT_PROJECT_ID = 'maint.project.id' INFRASTRUCTURE_PROJECT_ID = "infrastructure.project.id" + TOTAL_SLICE_COUNT_SEED = "total_slice_count_seed" ELASTIC_TIME = "request.elasticTime" ELASTIC_SIZE = "request.elasticSize" diff --git a/fabric_cf/actor/core/manage/actor_management_object.py b/fabric_cf/actor/core/manage/actor_management_object.py index 8a934f1d..597ce371 100644 --- a/fabric_cf/actor/core/manage/actor_management_object.py +++ b/fabric_cf/actor/core/manage/actor_management_object.py @@ -170,6 +170,26 @@ def get_slices(self, *, slice_id: ID, caller: AuthToken, slice_name: str = None, result.status = ManagementObject.set_exception_details(result=result.status, e=e) return result + def get_metrics(self, *, project_id: str, oidc_sub: str, excluded_projects: List[str] = None) -> list: + try: + return self.db.get_metrics(project_id=project_id, oidc_sub=oidc_sub, excluded_projects=excluded_projects) + except Exception as e: + self.logger.error("get_metrics {}".format(e)) + + def increment_metrics(self, *, project_id: str, oidc_sub: str, slice_count: int = 1) -> bool: + try: + return self.db.increment_metrics(project_id=project_id, oidc_sub=oidc_sub, slice_count=slice_count) + except Exception as e: + self.logger.error("add_or_update_metrics {}".format(e)) + + def get_slice_count(self, *, caller: AuthToken, email: str = None, states: List[int] = None, + project: str = None, user_id: str = None, excluded_projects: List[str] = None) -> int: + try: + return self.db.get_slice_count(email=email, states=states, project_id=project, oidc_sub=user_id) + except Exception as e: + self.logger.error("get_slice_count {}".format(e)) + return -1 + def add_slice(self, *, slice_obj: SliceAvro, caller: AuthToken) -> ResultStringAvro: result = ResultStringAvro() result.status = ResultAvro() diff --git a/fabric_cf/actor/core/manage/local/local_actor.py b/fabric_cf/actor/core/manage/local/local_actor.py index 028bdcf6..cdeea385 100644 --- a/fabric_cf/actor/core/manage/local/local_actor.py +++ b/fabric_cf/actor/core/manage/local/local_actor.py @@ -72,6 +72,30 @@ def get_slices(self, *, slice_id: ID = None, slice_name: str = None, email: str return None + def increment_metrics(self, *, project_id: str, oidc_sub: str, slice_count: int = 1) -> bool: + try: + return self.manager.increment_metrics(project_id=project_id, oidc_sub=oidc_sub, slice_count=slice_count) + except Exception as e: + self.on_exception(e=e, traceback_str=traceback.format_exc()) + return False + + def get_metrics(self, *, project_id: str, oidc_sub: str, excluded_projects: List[str] = None) -> list: + try: + return self.manager.get_metrics(project_id=project_id, oidc_sub=oidc_sub, + excluded_projects=excluded_projects) + except Exception as e: + self.on_exception(e=e, traceback_str=traceback.format_exc()) + + def get_slice_count(self, *, email: str = None, project: str = None, states: List[int] = None, + user_id: str = None, excluded_projects: List[str] = None) -> int: + try: + return self.manager.get_slice_count(caller=self.auth, states=states, email=email, project=project, + user_id=user_id, excluded_projects=excluded_projects) + except Exception as e: + self.on_exception(e=e, traceback_str=traceback.format_exc()) + + return -1 + def remove_slice(self, *, slice_id: ID) -> bool: self.clear_last() try: @@ -307,4 +331,4 @@ def get_poas(self, *, states: List[int] = None, slice_id: ID = None, rid: ID = N return result.poas except Exception as e: - self.on_exception(e=e, traceback_str=traceback.format_exc()) \ No newline at end of file + self.on_exception(e=e, traceback_str=traceback.format_exc()) diff --git a/fabric_cf/actor/core/plugins/db/actor_database.py b/fabric_cf/actor/core/plugins/db/actor_database.py index 76a86810..bebc0156 100644 --- a/fabric_cf/actor/core/plugins/db/actor_database.py +++ b/fabric_cf/actor/core/plugins/db/actor_database.py @@ -230,6 +230,46 @@ def get_slices(self, *, slice_id: ID = None, slice_name: str = None, project_id: self.lock.release() return result + def increment_metrics(self, *, project_id: str, oidc_sub: str, slice_count: int = 1) -> bool: + try: + self.lock.acquire() + self.db.increment_metrics(project_id=project_id, user_id=oidc_sub, slice_count=slice_count) + return True + except Exception as e: + self.logger.error(e) + self.logger.error(traceback.format_exc()) + finally: + if self.lock.locked(): + self.lock.release() + return False + + def get_metrics(self, *, project_id: str, oidc_sub: str, excluded_projects: List[str] = None) -> list: + try: + return self.db.get_metrics(project_id=project_id, user_id=oidc_sub, excluded_projects=excluded_projects) + except Exception as e: + self.logger.error(e) + self.logger.error(traceback.format_exc()) + finally: + if self.lock.locked(): + self.lock.release() + + def get_slice_count(self, *, project_id: str = None, email: str = None, states: list[int] = None, + oidc_sub: str = None, slc_type: List[SliceTypes] = None, + excluded_projects: List[str] = None) -> int: + try: + slice_type = [SliceTypes.ClientSlice.value] + if slc_type is not None: + slice_type = [x.value for x in slc_type] + return self.db.get_slice_count(project_id=project_id, email=email, states=states, oidc_sub=oidc_sub, + slc_type=slice_type, excluded_projects=excluded_projects) + except Exception as e: + self.logger.error(e) + self.logger.error(traceback.format_exc()) + finally: + if self.lock.locked(): + self.lock.release() + return -1 + def add_reservation(self, *, reservation: ABCReservationMixin): try: #self.lock.acquire() diff --git a/fabric_cf/actor/db/__init__.py b/fabric_cf/actor/db/__init__.py index 2f4dfcf8..8254565e 100644 --- a/fabric_cf/actor/db/__init__.py +++ b/fabric_cf/actor/db/__init__.py @@ -25,6 +25,7 @@ # Author: Komal Thareja (kthare10@renci.org) from sqlalchemy import JSON, ForeignKey, LargeBinary, Index, TIMESTAMP +from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import declarative_base from sqlalchemy import Column, String, Integer, Sequence from sqlalchemy.orm import relationship @@ -92,6 +93,17 @@ class Miscellaneous(Base): properties = Column(JSON) +class Metrics(Base): + """ + Represents Metrics Database Table + """ + __tablename__ = 'Metrics' + m_id = Column(Integer, Sequence('m_id', start=1, increment=1), autoincrement=True, primary_key=True) + user_id = Column(String, nullable=False, index=True) + project_id = Column(String, nullable=False, index=True) + slice_count = Column(Integer, nullable=False) + + class Proxies(Base): """ Represents Proxies Database Table diff --git a/fabric_cf/actor/db/psql_database.py b/fabric_cf/actor/db/psql_database.py index f0f5c5e7..304e4a76 100644 --- a/fabric_cf/actor/db/psql_database.py +++ b/fabric_cf/actor/db/psql_database.py @@ -36,7 +36,7 @@ from fabric_cf.actor.core.common.constants import Constants from fabric_cf.actor.core.common.exceptions import DatabaseException from fabric_cf.actor.db import Base, Clients, ConfigMappings, Proxies, Units, Reservations, Slices, ManagerObjects, \ - Miscellaneous, Actors, Delegations, Sites, Poas, Components + Miscellaneous, Actors, Delegations, Sites, Poas, Components, Metrics @contextmanager @@ -107,6 +107,7 @@ def reset_db(self): session.query(Actors).delete() session.query(Sites).delete() session.query(Poas).delete() + session.query(Metrics).delete() session.commit() except Exception as e: session.rollback() @@ -539,6 +540,40 @@ def create_slices_filter(*, slice_id: str = None, slice_name: str = None, projec filter_dict['oidc_claim_sub'] = oidc_sub return filter_dict + def get_slice_count(self, *, project_id: str = None, email: str = None, states: List[int] = None, + oidc_sub: str = None, slc_type: List[int] = None, excluded_projects: List[str]) -> int: + """ + Get slices count for an actor + @param project_id project id + @param email email + @param states states + @param oidc_sub oidc claim sub + @param slc_type slice type + @param excluded_projects excluded_projects + @return list of slices + """ + session = self.get_session() + try: + filter_dict = self.create_slices_filter(project_id=project_id, email=email, oidc_sub=oidc_sub) + + rows = session.query(Slices).filter_by(**filter_dict) + + rows = rows.order_by(desc(Slices.lease_end)) + + if states is not None: + rows = rows.filter(Slices.slc_state.in_(states)) + + if slc_type is not None: + rows = rows.filter(Slices.slc_type.in_(slc_type)) + + if excluded_projects is not None: + rows = rows.filter(Slices.project_id.notin_(excluded_projects)) + + return rows.count() + except Exception as e: + self.logger.error(Constants.EXCEPTION_OCCURRED.format(e)) + raise e + def get_slices(self, *, slice_id: str = None, slice_name: str = None, project_id: str = None, email: str = None, states: list[int] = None, oidc_sub: str = None, slc_type: list[int] = None, limit: int = None, offset: int = None, lease_end: datetime = None, search: str = None, @@ -1575,6 +1610,59 @@ def get_poas(self, *, poa_guid: str = None, project_id: str = None, email: str = raise e return result + def increment_metrics(self, *, project_id: str, user_id: str, slice_count: int = 1): + """ + Add or Update Metrics + @param project_id: project_id + @param user_id: user_id + @param slice_count: slice_count + """ + session = self.get_session() + try: + metric_obj = session.query(Metrics).filter_by(project_id=project_id, user_id=user_id).one_or_none() + if not metric_obj: + metric_obj = Metrics(project_id=project_id, user_id=user_id, slice_count=slice_count) + session.add(metric_obj) + else: + metric_obj.slice_count += slice_count + session.commit() + except Exception as e: + session.rollback() + self.logger.error(Constants.EXCEPTION_OCCURRED.format(e)) + raise e + + def get_metrics(self, *, project_id: str = None, user_id: str = None, excluded_projects: List[str] = None) -> list: + """ + Get Metric count + @param project_id: project_id + @param user_id: user_id + @param excluded_projects: excluded_projects + @return list of metrics + """ + result = [] + session = self.get_session() + try: + filter_criteria = True + # Construct filter condition + if project_id and user_id: + filter_criteria = and_(Metrics.project_id == project_id, Metrics.user_id == user_id) + elif project_id is not None: + filter_criteria = and_(Metrics.project_id == project_id) + elif user_id is not None: + filter_criteria = and_(Metrics.user_id == user_id) + + if excluded_projects: + filter_criteria = and_(Metrics.project_id.notin_(excluded_projects)) + + rows = session.query(Metrics).filter(filter_criteria).all() + + for r in rows: + result.append(self.generate_dict_from_row(row=r)) + return result + except Exception as e: + self.logger.error(Constants.EXCEPTION_OCCURRED.format(e)) + raise e + def test(): logger = logging.getLogger('PsqlDatabase') diff --git a/fabric_cf/orchestrator/config.orchestrator.yaml b/fabric_cf/orchestrator/config.orchestrator.yaml index f3534867..60e2ec43 100644 --- a/fabric_cf/orchestrator/config.orchestrator.yaml +++ b/fabric_cf/orchestrator/config.orchestrator.yaml @@ -49,6 +49,7 @@ runtime: rpc.request.timeout.seconds: 1200 maint.project.id: 990d8a8b-7e50-4d13-a3be-0f133ffa8653 infrastructure.project.id: 4604cab7-41ff-4c1a-a935-0ca6f20cceeb + total_slice_count_seed: 0 message.max.bytes: 1048588 rpc.retries: 5 commit.batch.size: 1 diff --git a/fabric_cf/orchestrator/core/orchestrator_handler.py b/fabric_cf/orchestrator/core/orchestrator_handler.py index 4c9d8323..0063cb6e 100644 --- a/fabric_cf/orchestrator/core/orchestrator_handler.py +++ b/fabric_cf/orchestrator/core/orchestrator_handler.py @@ -64,7 +64,9 @@ def __init__(self): self.logger = self.globals.get_logger() self.jwks_url = self.globals.get_config().get_oauth_config().get(Constants.PROPERTY_CONF_O_AUTH_JWKS_URL, None) self.pdp_config = self.globals.get_config().get_global_config().get_pdp_config() - self.infrastructure_project_id = self.globals.get_config().get_runtime_config().get(Constants.INFRASTRUCTURE_PROJECT_ID, None) + self.config = self.globals.get_config() + self.infrastructure_project_id = self.config.get_runtime_config().get(Constants.INFRASTRUCTURE_PROJECT_ID, None) + self.total_slice_count_seed = self.config.get_runtime_config().get(Constants.TOTAL_SLICE_COUNT_SEED, 0) self.local_bqm = self.globals.get_config().get_global_config().get_bqm_config().get( Constants.LOCAL_BQM, False) @@ -333,6 +335,7 @@ def create_slice(self, *, token: str, slice_name: str, slice_graph: str, ssh_key EventLoggerSingleton.get().log_slice_event(slice_object=slice_obj, action=ActionId.create, topology=topology) + controller.increment_metrics(project_id=project, oidc_sub=fabric_token.uuid) return ResponseBuilder.get_reservation_summary(res_list=computed_reservations) except Exception as e: if slice_id is not None and controller is not None and asm_graph is not None: @@ -955,3 +958,44 @@ def get_poas(self, *, token: str, sliver_id: str = None, poa_id: str = None, sta self.logger.error(traceback.format_exc()) self.logger.error(f"Exception occurred processing poa e: {e}") raise e + + def get_metrics_overview(self, *, token: str = None, excluded_projects: List[str] = None): + """ + Get metrics overview + """ + try: + controller = self.controller_state.get_management_actor() + self.logger.debug(f"get_metrics_overview invoked for Controller: {controller}") + + project = None + user_id = None + # Filter based on project_id and user_id when token is provided + if token: + fabric_token = self.__authorize_request(id_token=token, action_id=ActionId.query) + projects = fabric_token.projects + if len(projects) == 1: + project, tags, project_name = fabric_token.first_project + user_id = fabric_token.uuid + + active_states = SliceState.list_values_ex_closing_dead() + active_slice_count = controller.get_slice_count(states=active_states, user_id=user_id, project=project, + excluded_projects=excluded_projects) + non_active_metrics = controller.get_metrics(oidc_sub=user_id, project_id=project, + excluded_projects=excluded_projects) + total_slices = 0 + for m in non_active_metrics: + total_slices += m.get("slice_count", 0) + if not user_id and not project: + # Get Seed value from config + total_slices += self.total_slice_count_seed + result = { + "slices": { + "active_cumulative": active_slice_count, + "non_active_cumulative": total_slices + } + } + return result + except Exception as e: + self.logger.error(traceback.format_exc()) + self.logger.error(f"Exception occurred processing get_metrics_overview e: {e}") + raise e diff --git a/fabric_cf/orchestrator/nginx/default.conf b/fabric_cf/orchestrator/nginx/default.conf index 754c21c3..fb698444 100644 --- a/fabric_cf/orchestrator/nginx/default.conf +++ b/fabric_cf/orchestrator/nginx/default.conf @@ -36,7 +36,7 @@ server { proxy_pass http://orchestrator:8700; proxy_set_header Host $http_host; } - location /metrics { + location /prom/metrics { proxy_pass http://orchestrator:11000; proxy_set_header Host $http_host; } diff --git a/fabric_cf/orchestrator/openapi.json b/fabric_cf/orchestrator/openapi.json index 0e14db3c..5eb1610d 100644 --- a/fabric_cf/orchestrator/openapi.json +++ b/fabric_cf/orchestrator/openapi.json @@ -25,6 +25,10 @@ } ], "tags": [ + { + "name": "metrics", + "description": "Control Framework Metrics" + }, { "name": "slices", "description": "Slices in FABRIC" @@ -75,6 +79,93 @@ } } }, + "/metrics/overview": { + "get": { + "tags": [ + "metrics" + ], + "summary": "Control Framework metrics overview", + "description": "Control Framework metrics overview", + "parameters": [ + { + "name": "excluded_projects", + "in": "query", + "description": "List of projects to exclude from the metrics overview", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/metrics" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/status_400_bad_request" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/status_401_unauthorized" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/status_403_forbidden" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/status_404_not_found" + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/status_500_internal_server_error" + } + } + } + } + } + } + }, "/resources": { "get": { "tags": [ @@ -463,6 +554,8 @@ "Modifying", "ModifyOK", "ModifyError", + "AllocatedOK", + "AllocatedError", "All" ] } @@ -1198,95 +1291,6 @@ ] } }, - "/slices/redeem/{slice_id}": { - "post": { - "tags": [ - "slices" - ], - "summary": "Redeem resources for a slice requested in future via create", - "description": "Request to provision resources for a slice scheduled in advance via the create request once the schedule for the slice is current.\n", - "parameters": [ - { - "name": "slice_id", - "in": "path", - "description": "Slice identified by universally unique identifier", - "required": true, - "style": "simple", - "explode": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/status_200_ok_no_content" - } - } - } - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/status_400_bad_request" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/status_401_unauthorized" - } - } - } - }, - "403": { - "description": "Forbidden", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/status_403_forbidden" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/status_404_not_found" - } - } - } - }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/status_500_internal_server_error" - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, "/slices/delete/{slice_id}": { "delete": { "tags": [ @@ -2286,6 +2290,25 @@ } } }, + "metrics": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/status_200_ok_single" + }, + { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + }, "slices": { "type": "object", "allOf": [ diff --git a/fabric_cf/orchestrator/swagger_server/controllers/metrics_controller.py b/fabric_cf/orchestrator/swagger_server/controllers/metrics_controller.py new file mode 100644 index 00000000..410ec566 --- /dev/null +++ b/fabric_cf/orchestrator/swagger_server/controllers/metrics_controller.py @@ -0,0 +1,15 @@ +from fabric_cf.orchestrator.swagger_server.models.metrics import Metrics # noqa: E501 +from fabric_cf.orchestrator.swagger_server.response import metrics_controller as rc + + +def metrics_overview_get(excluded_projects=None): # noqa: E501 + """Control Framework metrics overview + + Control Framework metrics overview # noqa: E501 + + :param excluded_projects: List of projects to exclude from the metrics overview + :type excluded_projects: List[str] + + :rtype: Metrics + """ + return rc.metrics_overview_get(excluded_projects=excluded_projects) diff --git a/fabric_cf/orchestrator/swagger_server/controllers/slices_controller.py b/fabric_cf/orchestrator/swagger_server/controllers/slices_controller.py index 6de0b78f..ec643207 100644 --- a/fabric_cf/orchestrator/swagger_server/controllers/slices_controller.py +++ b/fabric_cf/orchestrator/swagger_server/controllers/slices_controller.py @@ -148,19 +148,6 @@ def slices_modify_slice_id_put(body, slice_id): # noqa: E501 return rc.slices_modify_slice_id_put(body, slice_id) -def slices_redeem_slice_id_post(slice_id): # noqa: E501 - """Redeem resources for a slice requested in future via create - - Request to provision resources for a slice scheduled in advance via the create request once the schedule for the slice is current. # noqa: E501 - - :param slice_id: Slice identified by universally unique identifier - :type slice_id: str - - :rtype: Status200OkNoContent - """ - return 'do some magic!' - - def slices_renew_slice_id_post(slice_id, lease_end_time): # noqa: E501 """Renew slice diff --git a/fabric_cf/orchestrator/swagger_server/models/__init__.py b/fabric_cf/orchestrator/swagger_server/models/__init__.py index a2ec9497..a43cb545 100644 --- a/fabric_cf/orchestrator/swagger_server/models/__init__.py +++ b/fabric_cf/orchestrator/swagger_server/models/__init__.py @@ -3,6 +3,7 @@ # flake8: noqa from __future__ import absolute_import # import models into model package +from fabric_cf.orchestrator.swagger_server.models.metrics import Metrics from fabric_cf.orchestrator.swagger_server.models.poa import Poa from fabric_cf.orchestrator.swagger_server.models.poa_data import PoaData from fabric_cf.orchestrator.swagger_server.models.poa_post import PoaPost diff --git a/fabric_cf/orchestrator/swagger_server/models/metrics.py b/fabric_cf/orchestrator/swagger_server/models/metrics.py new file mode 100644 index 00000000..84e52901 --- /dev/null +++ b/fabric_cf/orchestrator/swagger_server/models/metrics.py @@ -0,0 +1,141 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from fabric_cf.orchestrator.swagger_server.models.base_model_ import Model +from fabric_cf.orchestrator.swagger_server.models.status200_ok_single import Status200OkSingle # noqa: F401,E501 +from fabric_cf.orchestrator.swagger_server import util + + +class Metrics(Model): + """NOTE: This class is auto generated by the swagger code generator program. + + Do not edit the class manually. + """ + def __init__(self, size: int=1, status: int=200, type: str=None, results: List[object]=None): # noqa: E501 + """Metrics - a model defined in Swagger + + :param size: The size of this Metrics. # noqa: E501 + :type size: int + :param status: The status of this Metrics. # noqa: E501 + :type status: int + :param type: The type of this Metrics. # noqa: E501 + :type type: str + :param results: The results of this Metrics. # noqa: E501 + :type results: List[object] + """ + self.swagger_types = { + 'size': int, + 'status': int, + 'type': str, + 'results': List[object] + } + + self.attribute_map = { + 'size': 'size', + 'status': 'status', + 'type': 'type', + 'results': 'results' + } + self._size = size + self._status = status + self._type = type + self._results = results + + @classmethod + def from_dict(cls, dikt) -> 'Metrics': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The metrics of this Metrics. # noqa: E501 + :rtype: Metrics + """ + return util.deserialize_model(dikt, cls) + + @property + def size(self) -> int: + """Gets the size of this Metrics. + + + :return: The size of this Metrics. + :rtype: int + """ + return self._size + + @size.setter + def size(self, size: int): + """Sets the size of this Metrics. + + + :param size: The size of this Metrics. + :type size: int + """ + + self._size = size + + @property + def status(self) -> int: + """Gets the status of this Metrics. + + + :return: The status of this Metrics. + :rtype: int + """ + return self._status + + @status.setter + def status(self, status: int): + """Sets the status of this Metrics. + + + :param status: The status of this Metrics. + :type status: int + """ + + self._status = status + + @property + def type(self) -> str: + """Gets the type of this Metrics. + + + :return: The type of this Metrics. + :rtype: str + """ + return self._type + + @type.setter + def type(self, type: str): + """Sets the type of this Metrics. + + + :param type: The type of this Metrics. + :type type: str + """ + + self._type = type + + @property + def results(self) -> List[object]: + """Gets the results of this Metrics. + + + :return: The results of this Metrics. + :rtype: List[object] + """ + return self._results + + @results.setter + def results(self, results: List[object]): + """Sets the results of this Metrics. + + + :param results: The results of this Metrics. + :type results: List[object] + """ + + self._results = results diff --git a/fabric_cf/orchestrator/swagger_server/response/constants.py b/fabric_cf/orchestrator/swagger_server/response/constants.py index 32d33c99..62d8c88a 100644 --- a/fabric_cf/orchestrator/swagger_server/response/constants.py +++ b/fabric_cf/orchestrator/swagger_server/response/constants.py @@ -50,3 +50,5 @@ POAS_GET_POA_ID_PATH = '/poas/{poa_id}' VERSIONS_PATH = '/version' + +METRICS_GET_PATH = '/metrics/overview' diff --git a/fabric_cf/orchestrator/swagger_server/response/cors_response.py b/fabric_cf/orchestrator/swagger_server/response/cors_response.py index edf309e6..8efc4ed8 100644 --- a/fabric_cf/orchestrator/swagger_server/response/cors_response.py +++ b/fabric_cf/orchestrator/swagger_server/response/cors_response.py @@ -8,7 +8,7 @@ from fabric_cf.orchestrator.swagger_server.models import Resources, Slices, Slivers, Version, Status200OkNoContent, \ SliceDetails, Status200OkNoContentData, Status400BadRequestErrors, Status400BadRequest, Status401UnauthorizedErrors, \ Status401Unauthorized, Status403ForbiddenErrors, Status403Forbidden, Status404NotFoundErrors, Status404NotFound, \ - Status500InternalServerErrorErrors, Status500InternalServerError + Status500InternalServerErrorErrors, Status500InternalServerError, Metrics _INDENT = int(os.getenv('OC_API_JSON_RESPONSE_INDENT', '4')) @@ -51,7 +51,7 @@ def cors_response(req: request, status_code: int = 200, body: object = None, x_e def cors_200(response_body: Union[Resources, Slices, SliceDetails, Slivers, Version, - Status200OkNoContent] = None) -> cors_response: + Status200OkNoContent, Metrics] = None) -> cors_response: """ Return 200 - OK """ diff --git a/fabric_cf/orchestrator/swagger_server/response/metrics_controller.py b/fabric_cf/orchestrator/swagger_server/response/metrics_controller.py new file mode 100644 index 00000000..7f9f74a1 --- /dev/null +++ b/fabric_cf/orchestrator/swagger_server/response/metrics_controller.py @@ -0,0 +1,58 @@ +from typing import List + +from fabric_cf.orchestrator.swagger_server.response.utils import get_token, cors_error_response, cors_success_response + +from fabric_cf.orchestrator.swagger_server.response.constants import GET_METHOD, METRICS_GET_PATH + +from fabric_cf.orchestrator.swagger_server import received_counter, success_counter, failure_counter + +from fabric_cf.orchestrator.core.orchestrator_handler import OrchestratorHandler + +from fabric_cf.orchestrator.swagger_server.response.cors_response import cors_200 + +from fabric_cf.orchestrator.swagger_server.models import Metrics + + +def metrics_overview_get(excluded_projects: List[str] = None) -> Metrics: # noqa: E501 + """Control Framework metrics overview + { + "results": [ + { + "last_updated": "2024-04-02 19:50:00.00+00", + "slices": { + "active_cumulative": 164, + "non_active_cumulative": 0 + } + } + ], + "size": 1, + "status": 200, + "type": "metrics.overview" + } + + :rtype: Metrics + """ + handler = OrchestratorHandler() + logger = handler.get_logger() + received_counter.labels(GET_METHOD, METRICS_GET_PATH).inc() + try: + token = get_token() + metrics = handler.get_metrics_overview(token=token, excluded_projects=excluded_projects) + response = Metrics() + if metrics: + if isinstance(metrics, list): + response.results = metrics + else: + response.results = [metrics] + else: + response.results = [] + + response.size = len(response.results) + response.status = 200 + response.type = 'metrics.overview' + success_counter.labels(GET_METHOD, METRICS_GET_PATH).inc() + return cors_success_response(response_body=response) + except Exception as e: + logger.exception(e) + failure_counter.labels(GET_METHOD, METRICS_GET_PATH).inc() + return cors_error_response(error=e) diff --git a/fabric_cf/orchestrator/swagger_server/swagger/swagger.yaml b/fabric_cf/orchestrator/swagger_server/swagger/swagger.yaml index edd0e2bb..687ef854 100644 --- a/fabric_cf/orchestrator/swagger_server/swagger/swagger.yaml +++ b/fabric_cf/orchestrator/swagger_server/swagger/swagger.yaml @@ -16,6 +16,8 @@ servers: - url: https://virtserver.swaggerhub.com/kthare10/orchestrator/1.0.1 description: SwaggerHub API Auto Mocking tags: +- name: metrics + description: Control Framework Metrics - name: slices description: Slices in FABRIC - name: slivers @@ -46,6 +48,62 @@ paths: schema: $ref: '#/components/schemas/status_500_internal_server_error' x-openapi-router-controller: fabric_cf.orchestrator.swagger_server.controllers.version_controller + /metrics/overview: + get: + tags: + - metrics + summary: Control Framework metrics overview + description: Control Framework metrics overview + operationId: metrics_overview_get + parameters: + - name: excluded_projects + in: query + description: List of projects to exclude from the metrics overview + required: false + style: form + explode: true + schema: + type: array + items: + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/metrics' + "400": + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/status_400_bad_request' + "401": + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/status_401_unauthorized' + "403": + description: Forbidden + content: + application/json: + schema: + $ref: '#/components/schemas/status_403_forbidden' + "404": + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/status_404_not_found' + "500": + description: Internal Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/status_500_internal_server_error' + x-openapi-router-controller: fabric_cf.orchestrator.swagger_server.controllers.metrics_controller /resources: get: tags: @@ -834,63 +892,6 @@ paths: security: - bearerAuth: [] x-openapi-router-controller: fabric_cf.orchestrator.swagger_server.controllers.slices_controller - /slices/redeem/{slice_id}: - post: - tags: - - slices - summary: Redeem resources for a slice requested in future via create - description: | - Request to provision resources for a slice scheduled in advance via the create request once the schedule for the slice is current. - operationId: slices_redeem_slice_id_post - parameters: - - name: slice_id - in: path - description: Slice identified by universally unique identifier - required: true - style: simple - explode: false - schema: - type: string - responses: - "200": - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/status_200_ok_no_content' - "400": - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/status_400_bad_request' - "401": - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/status_401_unauthorized' - "403": - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/status_403_forbidden' - "404": - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/status_404_not_found' - "500": - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/status_500_internal_server_error' - security: - - bearerAuth: [] - x-openapi-router-controller: fabric_cf.orchestrator.swagger_server.controllers.slices_controller /slices/delete/{slice_id}: delete: tags: @@ -1564,6 +1565,16 @@ components: default: Internal Server Error details: type: string + metrics: + type: object + allOf: + - $ref: '#/components/schemas/status_200_ok_single' + - type: object + properties: + results: + type: array + items: + type: object slices: type: object allOf: diff --git a/fabric_cf/orchestrator/swagger_server/test/test_metrics_controller.py b/fabric_cf/orchestrator/swagger_server/test/test_metrics_controller.py new file mode 100644 index 00000000..80552d13 --- /dev/null +++ b/fabric_cf/orchestrator/swagger_server/test/test_metrics_controller.py @@ -0,0 +1,36 @@ +# coding: utf-8 + +from __future__ import absolute_import + +from flask import json +from six import BytesIO + +from fabric_cf.orchestrator.swagger_server.models.metrics import Metrics # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status400_bad_request import Status400BadRequest # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status401_unauthorized import Status401Unauthorized # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status403_forbidden import Status403Forbidden # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status404_not_found import Status404NotFound # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status500_internal_server_error import Status500InternalServerError # noqa: E501 +from fabric_cf.orchestrator.swagger_server.test import BaseTestCase + + +class TestMetricsController(BaseTestCase): + """MetricsController integration test stubs""" + + def test_metrics_overview_get(self): + """Test case for metrics_overview_get + + Control Framework metrics overview + """ + query_string = [('excluded_projects', 'excluded_projects_example')] + response = self.client.open( + '//metrics/overview', + method='GET', + query_string=query_string) + self.assert200(response, + 'Response body is : ' + response.data.decode('utf-8')) + + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/fabric_cf/orchestrator/swagger_server/test/test_poas_controller.py b/fabric_cf/orchestrator/swagger_server/test/test_poas_controller.py index 29d62e60..291c37d0 100644 --- a/fabric_cf/orchestrator/swagger_server/test/test_poas_controller.py +++ b/fabric_cf/orchestrator/swagger_server/test/test_poas_controller.py @@ -25,7 +25,7 @@ def test_poas_create_sliver_id_post(self): """ body = PoaPost() response = self.client.open( - '/poas/create/{sliver_id}'.format(sliver_id='sliver_id_example'), + '//poas/create/{sliver_id}'.format(sliver_id='sliver_id_example'), method='POST', data=json.dumps(body), content_type='application/json') @@ -42,7 +42,7 @@ def test_poas_get(self): ('limit', 200), ('offset', 1)] response = self.client.open( - '/poas/', + '//poas/', method='GET', query_string=query_string) self.assert200(response, @@ -54,7 +54,7 @@ def test_poas_poa_id_get(self): Perform an operational action on a sliver. """ response = self.client.open( - '/poas/{poa_id}'.format(poa_id='poa_id_example'), + '//poas/{poa_id}'.format(poa_id='poa_id_example'), method='GET') self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) diff --git a/fabric_cf/orchestrator/swagger_server/test/test_resources_controller.py b/fabric_cf/orchestrator/swagger_server/test/test_resources_controller.py index c971f079..6285d36b 100644 --- a/fabric_cf/orchestrator/swagger_server/test/test_resources_controller.py +++ b/fabric_cf/orchestrator/swagger_server/test/test_resources_controller.py @@ -5,13 +5,13 @@ from flask import json from six import BytesIO -from fabric_cf.orchestrator.fabric_cf.orchestrator.swagger_server.models.resources import Resources # noqa: E501 -from fabric_cf.orchestrator.fabric_cf.orchestrator.swagger_server.models.status400_bad_request import Status400BadRequest # noqa: E501 -from fabric_cf.orchestrator.fabric_cf.orchestrator.swagger_server.models.status401_unauthorized import Status401Unauthorized # noqa: E501 -from fabric_cf.orchestrator.fabric_cf.orchestrator.swagger_server.models.status403_forbidden import Status403Forbidden # noqa: E501 -from fabric_cf.orchestrator.fabric_cf.orchestrator.swagger_server.models.status404_not_found import Status404NotFound # noqa: E501 -from fabric_cf.orchestrator.fabric_cf.orchestrator.swagger_server.models.status500_internal_server_error import Status500InternalServerError # noqa: E501 -from fabric_cf.orchestrator.fabric_cf.orchestrator.swagger_server.test import BaseTestCase +from fabric_cf.orchestrator.swagger_server.models.resources import Resources # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status400_bad_request import Status400BadRequest # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status401_unauthorized import Status401Unauthorized # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status403_forbidden import Status403Forbidden # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status404_not_found import Status404NotFound # noqa: E501 +from fabric_cf.orchestrator.swagger_server.models.status500_internal_server_error import Status500InternalServerError # noqa: E501 +from fabric_cf.orchestrator.swagger_server.test import BaseTestCase class TestResourcesController(BaseTestCase): @@ -30,7 +30,7 @@ def test_portalresources_get(self): ('includes', 'includes_example'), ('excludes', 'excludes_example')] response = self.client.open( - '/portalresources', + '//portalresources', method='GET', query_string=query_string) self.assert200(response, @@ -48,7 +48,7 @@ def test_resources_get(self): ('includes', 'includes_example'), ('excludes', 'excludes_example')] response = self.client.open( - '/resources', + '//resources', method='GET', query_string=query_string) self.assert200(response, diff --git a/fabric_cf/orchestrator/swagger_server/test/test_slices_controller.py b/fabric_cf/orchestrator/swagger_server/test/test_slices_controller.py index 39b20a6d..88edcbc9 100644 --- a/fabric_cf/orchestrator/swagger_server/test/test_slices_controller.py +++ b/fabric_cf/orchestrator/swagger_server/test/test_slices_controller.py @@ -20,7 +20,6 @@ class TestSlicesController(BaseTestCase): """SlicesController integration test stubs""" - TOKEN = "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImI0MTUxNjcyMTExOTFlMmUwNWIyMmI1NGIxZDNiNzY2N2U3NjRhNzQ3NzIyMTg1ZTcyMmU1MmUxNDZmZTQzYWEiLCJ0eXAiOiJKV1QifQ.eyJhY3IiOiJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydCIsImVtYWlsIjoia3RoYXJlMTBAZW1haWwudW5jLmVkdSIsImdpdmVuX25hbWUiOiJLb21hbCIsImZhbWlseV9uYW1lIjoiVGhhcmVqYSIsIm5hbWUiOiJLb21hbCBUaGFyZWphIiwiaXNzIjoiaHR0cHM6Ly9jaWxvZ29uLm9yZyIsInN1YiI6Imh0dHA6Ly9jaWxvZ29uLm9yZy9zZXJ2ZXJBL3VzZXJzLzExOTA0MTAxIiwiYXVkIjoiY2lsb2dvbjovY2xpZW50X2lkLzYxN2NlY2RkNzRlMzJiZTRkODE4Y2ExMTUxNTMxZGZmIiwianRpIjoiaHR0cHM6Ly9jaWxvZ29uLm9yZy9vYXV0aDIvaWRUb2tlbi8yNjg0N2EzODcwN2Y5YTk4Y2RmYjEwYjY5OThiNzBkLzE2ODkyNjkwNjU3OTIiLCJhdXRoX3RpbWUiOjE2ODkyNjc4MzgsImV4cCI6MTY4OTI4MzQ2OSwiaWF0IjoxNjg5MjY5MDY5LCJwcm9qZWN0cyI6W3sibmFtZSI6IkNGIFRlc3QiLCJ1dWlkIjoiMTBjMDA5NGEtYWJhZi00ZWY5LWE1MzItMmJlNTNlMmE4OTZiIiwidGFncyI6WyJDb21wb25lbnQuR1BVIiwiQ29tcG9uZW50LlN0b3JhZ2UiXSwibWVtYmVyc2hpcHMiOnsiaXNfY3JlYXRvciI6dHJ1ZSwiaXNfbWVtYmVyIjp0cnVlLCJpc19vd25lciI6dHJ1ZX19XSwicm9sZXMiOlt7ImRlc2NyaXB0aW9uIjoiQ0YgVGVzdCBhbmQgdGVzdCBhbmQgdGVzdCIsIm5hbWUiOiIxMGMwMDk0YS1hYmFmLTRlZjktYTUzMi0yYmU1M2UyYTg5NmItcGMifSx7ImRlc2NyaXB0aW9uIjoiQ0YgVGVzdCBhbmQgdGVzdCBhbmQgdGVzdCIsIm5hbWUiOiIxMGMwMDk0YS1hYmFmLTRlZjktYTUzMi0yYmU1M2UyYTg5NmItcG0ifSx7ImRlc2NyaXB0aW9uIjoiQ0YgVGVzdCBhbmQgdGVzdCBhbmQgdGVzdCIsIm5hbWUiOiIxMGMwMDk0YS1hYmFmLTRlZjktYTUzMi0yYmU1M2UyYTg5NmItcG8ifSx7ImRlc2NyaXB0aW9uIjoiRkFCUklDIFByb2plY3QiLCJuYW1lIjoiOGIzYTJlYWUtYTBjMC00NzVhLTgwN2ItZTlhZjU4MWNlNGMwLXBtIn0seyJkZXNjcmlwdGlvbiI6IlByb2plY3QtVGFncyIsIm5hbWUiOiJiOGQ2NmZiMy1lN2FkLTRkZjktYTY1Mi0yZDhlMzIzMjM2ZTUtcGMifSx7ImRlc2NyaXB0aW9uIjoiUHJvamVjdC1UYWdzIiwibmFtZSI6ImI4ZDY2ZmIzLWU3YWQtNGRmOS1hNjUyLTJkOGUzMjMyMzZlNS1wbyJ9LHsiZGVzY3JpcHRpb24iOiJBY3RpdmUgVXNlcnMgb2YgRkFCUklDIC0gaW5pdGlhbGx5IHNldCBieSBlbnJvbGxtZW50IHdvcmtmbG93IiwibmFtZSI6ImZhYnJpYy1hY3RpdmUtdXNlcnMifSx7ImRlc2NyaXB0aW9uIjoiRmFjaWxpdHkgT3BlcmF0b3JzIGZvciBGQUJSSUMiLCJuYW1lIjoiZmFjaWxpdHktb3BlcmF0b3JzIn0seyJkZXNjcmlwdGlvbiI6IiBKdXB5dGVyaHViIGFjY2VzcyAtIGJhc2VkIG9uIHByb2plY3QgcGFydGljaXBhdGlvbiIsIm5hbWUiOiJKdXB5dGVyaHViIn0seyJkZXNjcmlwdGlvbiI6IlByb2plY3QgTGVhZHMgZm9yIEZBQlJJQyIsIm5hbWUiOiJwcm9qZWN0LWxlYWRzIn1dLCJzY29wZSI6ImFsbCIsInV1aWQiOiIyMjY1YTRkYS1lMWZjLTRmZmMtYmJiNy1kODZkNTY1NzViZmYifQ.OG_m48gCzMt8vcYv947cZduJSbEEzpMuBbbP59SgfD7q1q4_kMbBg36P_SmZMaRfZ6P65hfEdRSnX1x5i4OJQkE47sw1P0Uge6klcnfORIwUyMNphNoKgUcbLRZN9Kch6xKr6JPEfnXKnTdTUMS2-cKzmgLa5w2oIH8kipKisHey7PQhwfdZhwqR8hme5Q7Gwf4O3n45jA8HQQxaO38scIOy0NajQOMPvOkQvfzWOOv79mSztepN2jlJRMGWLqdBql5kSm_xtVRk3S3SdLuS_GTKyA4zfU1-ouT-NUlE9CM86mBHy4FYki5M-cnM3Us3RI7oAxal8kAGqB2I0LY-xMkhHY6k34FCCHiFWvH4WgYmWBEWO7U8uPUq1rbapX6NluQJaSxc54UEA33B9pC_Cgkod6UzB_7g_CNmS31wajjyulCEjIBtlBWTXdmblG8PEZA0_T8DrXh7NPPxF3XrRC74d-IqQ9WiTuH6qrOrMT3ivpeZqPFdriKOXB49EREmUV1iO-STWXRG1RDBLM-lGW7dWOfgsNmlEvW49A8ZO6-T7xVYyVbsVB0XF9oRKAr3uMt_N9ZgF_BP3CKzIi5bhvr4_0AyFifgbrkaKb4qIMOj0XD-Ds1cCDBASqiIj0peal9M8BlBDDMY_80MkRxH1i-XvLRYU5s9t3Oc3p1yd4U" def test_slices_create_post(self): """Test case for slices_create_post @@ -32,7 +31,7 @@ def test_slices_create_post(self): ('ssh_key', 'ssh_key_example'), ('lease_end_time', 'lease_end_time_example')] response = self.client.open( - '/slices/create', + '//slices/create', method='POST', data=json.dumps(body), content_type='application/json', @@ -50,7 +49,7 @@ def test_slices_creates_post(self): ('lease_start_time', 'lease_start_time_example'), ('lease_end_time', 'lease_end_time_example')] response = self.client.open( - '/slices/creates', + '//slices/creates', method='POST', data=json.dumps(body), content_type='application/json', @@ -64,7 +63,7 @@ def test_slices_delete_delete(self): Delete all slices for a User within a project. """ response = self.client.open( - '/slices/delete', + '//slices/delete', method='DELETE') self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) @@ -75,8 +74,8 @@ def test_slices_delete_slice_id_delete(self): Delete slice. """ response = self.client.open( - '/slices/delete/{slice_id}'.format(slice_id='slice_id_example'), - method='DELETE', ) + '//slices/delete/{slice_id}'.format(slice_id='slice_id_example'), + method='DELETE') self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) @@ -90,15 +89,12 @@ def test_slices_get(self): ('exact_match', false), ('as_self', true), ('states', 'states_example'), - ('as_self', True), ('limit', 200), - ('offset', 1) - ] + ('offset', 1)] response = self.client.open( - '/slices', + '//slices', method='GET', - query_string=query_string, headers={'AUTHORIZATION': self.TOKEN} - ) + query_string=query_string) self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) @@ -108,7 +104,7 @@ def test_slices_modify_slice_id_accept_post(self): Accept the last modify an existing slice """ response = self.client.open( - '/slices/modify/{slice_id}/accept'.format(slice_id='slice_id_example'), + '//slices/modify/{slice_id}/accept'.format(slice_id='slice_id_example'), method='POST') self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) @@ -120,24 +116,13 @@ def test_slices_modify_slice_id_put(self): """ body = 'body_example' response = self.client.open( - '/slices/modify/{slice_id}'.format(slice_id='slice_id_example'), + '//slices/modify/{slice_id}'.format(slice_id='slice_id_example'), method='PUT', data=json.dumps(body), content_type='text/plain') self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) - def test_slices_redeem_slice_id_post(self): - """Test case for slices_redeem_slice_id_post - - Redeem resources for a slice requested in future via create - """ - response = self.client.open( - '//slices/redeem/{slice_id}'.format(slice_id='slice_id_example'), - method='POST') - self.assert200(response, - 'Response body is : ' + response.data.decode('utf-8')) - def test_slices_renew_slice_id_post(self): """Test case for slices_renew_slice_id_post @@ -145,7 +130,7 @@ def test_slices_renew_slice_id_post(self): """ query_string = [('lease_end_time', 'lease_end_time_example')] response = self.client.open( - '/slices/renew/{slice_id}'.format(slice_id='slice_id_example'), + '//slices/renew/{slice_id}'.format(slice_id='slice_id_example'), method='POST', query_string=query_string) self.assert200(response, @@ -156,10 +141,10 @@ def test_slices_slice_id_get(self): slice properties """ - query_string = [('as_self', True), + query_string = [('as_self', true), ('graph_format', 'GRAPHML')] response = self.client.open( - '/slices/{slice_id}'.format(slice_id='slice_id_example'), + '//slices/{slice_id}'.format(slice_id='slice_id_example'), method='GET', query_string=query_string) self.assert200(response, diff --git a/fabric_cf/orchestrator/swagger_server/test/test_slivers_controller.py b/fabric_cf/orchestrator/swagger_server/test/test_slivers_controller.py index 24659957..ee1b58cb 100644 --- a/fabric_cf/orchestrator/swagger_server/test/test_slivers_controller.py +++ b/fabric_cf/orchestrator/swagger_server/test/test_slivers_controller.py @@ -23,9 +23,9 @@ def test_slivers_get(self): Retrieve a listing of user slivers """ query_string = [('slice_id', 'slice_id_example'), - ('as_self', True)] + ('as_self', true)] response = self.client.open( - '/slivers', + '//slivers', method='GET', query_string=query_string) self.assert200(response, @@ -37,9 +37,9 @@ def test_slivers_sliver_id_get(self): slivers properties """ query_string = [('slice_id', 'slice_id_example'), - ('as_self', True)] + ('as_self', true)] response = self.client.open( - '/slivers/{sliver_id}'.format(sliver_id='sliver_id_example'), + '//slivers/{sliver_id}'.format(sliver_id='sliver_id_example'), method='GET', query_string=query_string) self.assert200(response, diff --git a/fabric_cf/orchestrator/swagger_server/test/test_version_controller.py b/fabric_cf/orchestrator/swagger_server/test/test_version_controller.py index 29bfa789..ad073fe7 100644 --- a/fabric_cf/orchestrator/swagger_server/test/test_version_controller.py +++ b/fabric_cf/orchestrator/swagger_server/test/test_version_controller.py @@ -19,9 +19,8 @@ def test_version_get(self): Version """ response = self.client.open( - '/version', + '//version', method='GET') - print(response.data) self.assert200(response, 'Response body is : ' + response.data.decode('utf-8')) diff --git a/psql.upgrade b/psql.upgrade index 228eab41..a6a6e9b9 100644 --- a/psql.upgrade +++ b/psql.upgrade @@ -72,3 +72,10 @@ ALTER TABLE "Poas" DROP COLUMN last_update_time; -- Rename the new columns to the original column names ALTER TABLE "Poas" RENAME COLUMN last_update_time_with_tz TO last_update_time; + +CREATE TABLE IF NOT EXISTS "Metrics" ( + m_id INTEGER NOT NULL DEFAULT nextval('m_id') PRIMARY KEY, + user_id VARCHAR NOT NULL, + project_id VARCHAR NOT NULL, + slice_count INTEGER NOT NULL, +); \ No newline at end of file