From 9ef19ff5b0f53ea7c3f97f397c78620db72d3e70 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Sat, 3 Dec 2022 01:02:17 -0500 Subject: [PATCH 01/10] support for maint mode --- fabric_mgmt_cli/managecli/manage_command.py | 39 +++++- fabric_mgmt_cli/managecli/managecli.py | 69 ++++++++-- fabric_mgmt_cli/managecli/show_command.py | 135 +++++++++++++++++--- requirements.txt | 9 +- 4 files changed, 209 insertions(+), 43 deletions(-) diff --git a/fabric_mgmt_cli/managecli/manage_command.py b/fabric_mgmt_cli/managecli/manage_command.py index 3643148..f99532e 100644 --- a/fabric_mgmt_cli/managecli/manage_command.py +++ b/fabric_mgmt_cli/managecli/manage_command.py @@ -24,13 +24,17 @@ # # Author: Komal Thareja (kthare10@renci.org) import traceback +from datetime import datetime, timezone from typing import Tuple from fabric_cf.actor.core.apis.abc_delegation import DelegationState +from fabric_cf.actor.core.common.constants import Constants +from fabric_cf.actor.core.container.maintenance import MaintenanceState from fabric_cf.actor.core.kernel.slice_state_machine import SliceState from fabric_cf.actor.core.manage.error import Error from fabric_cf.actor.core.util.id import ID from fabric_mb.message_bus.messages.delegation_avro import DelegationAvro +from fabric_mb.message_bus.messages.site_avro import SiteAvro from fabric_mb.message_bus.messages.slice_avro import SliceAvro from fabric_mgmt_cli.managecli.show_command import ShowCommand @@ -361,13 +365,19 @@ def reclaim_delegations(self, *, broker: str, am: str, callback_topic: str, did: self.logger.error(f"Exception occurred e: {e}") self.logger.error(traceback.format_exc()) - def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, mode: bool = False, + def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, mode: str, projects: str = None, + users: str = None, site_name: str = None, workers: str = None, deadline: str = None, id_token: str = None): """ Claim delegations @param actor_name actor name @param callback_topic callback topic @param mode mode + @param projects comma separated list of project_ids allowed in maintenance + @param users comma separated list of email address of the users allowed in maintenance + @param site_name site name + @param workers comma separated list of specific workers on a site which are in maintenance + @param deadline start time for the Maintenance @param id_token id token """ status = False @@ -378,11 +388,32 @@ def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, mode: if actor is None: raise Exception(f"Invalid arguments! {actor_name} not found") + mode = MaintenanceState.translate_string_to_state(state_string=mode.lower()) + mode_value = mode.value + + if mode == MaintenanceState.PreMaint and deadline is None: + raise Exception("Required parameter: deadline is missing!") + + if deadline is not None: + try: + maint_start_time = datetime.strptime(deadline, Constants.LEASE_TIME_FORMAT) + except Exception as e: + raise Exception(f"Deadline is not in format {Constants.LEASE_TIME_FORMAT}") + now = datetime.now(timezone.utc) + if maint_start_time < now: + raise Exception(f"Deadline cannot be before current time {now}") + try: actor.prepare(callback_topic=callback_topic) + sites = None + if site_name is not None: + site_avro = SiteAvro(name=site_name, state=mode_value, workers=workers, deadline=deadline) + sites = [site_avro] + mode_value = None + + status = actor.toggle_maintenance_mode(actor_guid=str(actor.get_guid()), mode=mode_value, sites=sites, + projects=projects, users=users, callback_topic=callback_topic) - status = actor.toggle_maintenance_mode(actor_guid=str(actor.get_guid()), - mode=mode, callback_topic=callback_topic) except Exception as e: self.logger.error(f"Exception occurred e: {e}") self.logger.error(traceback.format_exc()) @@ -396,7 +427,7 @@ def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, mode: if status: print(f"Maintenance mode successfully set to {mode}") else: - print(f"Failure to set maintenance mode error {error}") + print(f"Failure to set maintenance mode: [{mode}]; Error: [{error}]") def delete_dead_slices(self, *, actor_name: str, callback_topic: str, id_token: str, email: str): diff --git a/fabric_mgmt_cli/managecli/managecli.py b/fabric_mgmt_cli/managecli/managecli.py index b22dc8f..95caad3 100644 --- a/fabric_mgmt_cli/managecli/managecli.py +++ b/fabric_mgmt_cli/managecli/managecli.py @@ -124,15 +124,17 @@ def removealldead(ctx, email, actor, idtoken, refreshtoken): type=click.Choice(['nascent', 'configuring', 'stableok', 'stableerror', 'modifyok', 'modifyerror', 'closing', 'dead'], case_sensitive=False), required=False) +@click.option('--format', default='text', help='Output Format Type: text or json', required=False) @click.pass_context -def query(ctx, actor, sliceid, slicename, idtoken, refreshtoken, email, state): +def query(ctx, actor, sliceid, slicename, idtoken, refreshtoken, email, state, format): """ Get slice(s) from an actor """ try: idtoken = KafkaProcessorSingleton.get().start(id_token=idtoken, refresh_token=refreshtoken, ignore_tokens=True) mgmt_command = ShowCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.get_slices(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - slice_id=sliceid, slice_name=slicename, id_token=idtoken, email=email, state=state) + slice_id=sliceid, slice_name=slicename, id_token=idtoken, email=email, state=state, + format=format) KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() @@ -221,8 +223,15 @@ def remove(ctx, sliverid, actor, idtoken, refreshtoken): @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @click.option('--email', default=None, help='User Email', required=False) +@click.option('--site', default=None, help='Site Name', required=False) +@click.option('--type', default=None, + help='Sliver Type, possible allowed values: ' + '[VM, L2Bridge, L2STS, L2PTP, FABNetv4, FABNetv6, FABNetv4Ext, FABNetv6Ext, PortMirror, Facility, ' + 'L3VPN]', + required=False) +@click.option('--format', default='text', help='Output Format Type: text or json', required=False) @click.pass_context -def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email): +def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email, site, type, format): """ Get sliver(s) from an actor """ try: @@ -230,7 +239,8 @@ def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email): mgmt_command = ShowCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.get_reservations(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - slice_id=sliceid, rid=sliverid, state=state, id_token=idtoken, email=email) + slice_id=sliceid, rid=sliverid, state=state, id_token=idtoken, email=email, + site=site, type=type, format=format) KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() @@ -303,8 +313,9 @@ def reclaim(ctx, broker: str, am: str, did: str, idtoken, refreshtoken): default='all', help='Sliver State', required=False) @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) +@click.option('--format', default='text', help='Output Format Type: text or json', required=False) @click.pass_context -def query(ctx, actor, sliceid, did, state, idtoken, refreshtoken): +def query(ctx, actor, sliceid, did, state, idtoken, refreshtoken, format): """ Get delegation(s) from an actor """ try: @@ -312,7 +323,7 @@ def query(ctx, actor, sliceid, did, state, idtoken, refreshtoken): mgmt_command = ShowCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.get_delegations(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - slice_id=sliceid, did=did, state=state, id_token=idtoken) + slice_id=sliceid, did=did, state=state, id_token=idtoken, format=format) KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() @@ -375,19 +386,57 @@ def maintenance(ctx): @maintenance.command() @click.option('--actor', help='Actor Name', required=True) -@click.option('--mode', help='Mode value, i.e. True (Enabled) or False (Disabled)', default=True, required=False) +@click.option('--mode', help='Mode value, i.e. PreMaint, Maint, NoMaint', required=True) +@click.option('--projects', help='Comma separated list of Project Ids allowed to use TestBed in Maintenance mode', + required=False, default=None) +@click.option('--users', help='Comma separated list of User emails allowed to use TestBed in Maintenance mode', + required=False, default=None) @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @click.pass_context -def setmode(ctx, actor: str, mode: bool, idtoken: str, refreshtoken: str): - """ Enable/Disable Maintenance Mode for an actor +def testbed(ctx, actor: str, mode: str, projects: str, users: str, idtoken: str, refreshtoken: str): + """ Change Maintenance modes (PreMaint, Maint, NoMaint) for the Testbed """ try: idtoken = KafkaProcessorSingleton.get().start(id_token=idtoken, refresh_token=refreshtoken, ignore_tokens=True) mgmt_command = ManageCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.toggle_maintenance_mode(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - mode=mode, id_token=idtoken) + mode=mode, projects=projects, users=users, id_token=idtoken) + KafkaProcessorSingleton.get().stop() + except Exception as e: + # traceback.print_exc() + click.echo('Error occurred: {}'.format(e)) + + +@maintenance.command() +@click.option('--actor', help='Actor Name', required=True) +@click.option('--name', help='Site Name', required=True) +@click.option('--mode', help='Mode value, i.e. PreMaint, Maint, NoMaint', required=True) +@click.option('--projects', help='Comma separated list of Project Ids allowed to use TestBed in Maintenance mode', + required=False, default=None) +@click.option('--users', help='Comma separated list of User emails allowed to use TestBed in Maintenance mode', + required=False, default=None) +@click.option('--workers', help='Comma separated list of workers to be marked in Maintenance mode', + required=False, default=None) +@click.option('--deadline', + help='Start time that allows new resources to be created or extended up until stated deadline in format: %Y-%m-%d %H:%M:%S %z', + required=False, default=None) +@click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) +@click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) +@click.pass_context +def site(ctx, actor: str, name: str, mode: str, projects, users, workers: str, deadline: str, + idtoken: str, refreshtoken: str): + """ Change Maintenance modes (PreMaint, Maint, NoMaint) for a specific Site or a specific worker + """ + try: + idtoken = KafkaProcessorSingleton.get().start(id_token=idtoken, refresh_token=refreshtoken, ignore_tokens=True) + mgmt_command = ManageCommand(logger=KafkaProcessorSingleton.get().logger) + mgmt_command.toggle_maintenance_mode(actor_name=actor, + callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), + mode=mode, projects=projects, users=users, + site_name=name, workers=workers, deadline=deadline, id_token=idtoken) + KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index 1602ec4..b4750fc 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -23,6 +23,7 @@ # # # Author: Komal Thareja (kthare10@renci.org) +import json import traceback from typing import Tuple, List @@ -33,9 +34,11 @@ from fabric_cf.actor.core.manage.error import Error from fabric_cf.actor.core.time.actor_clock import ActorClock from fabric_cf.actor.core.util.id import ID +from fabric_cf.actor.core.util.utils import sliver_to_str from fabric_mb.message_bus.messages.delegation_avro import DelegationAvro from fabric_mb.message_bus.messages.reservation_mng import ReservationMng from fabric_mb.message_bus.messages.slice_avro import SliceAvro +from fim.graph.abc_property_graph import ABCPropertyGraph from fim.slivers.network_node import NodeSliver from fim.slivers.network_service import NetworkServiceSliver @@ -44,13 +47,12 @@ class ShowCommand(Command): def get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str, slice_name: str, id_token: str, - email: str, state: str): + email: str, state: str, format: str): try: slices, error = self.do_get_slices(actor_name=actor_name, callback_topic=callback_topic, slice_id=slice_id, slice_name=slice_name, id_token=id_token, email=email, state=state) if slices is not None and len(slices) > 0: - for s in slices: - self.__print_slice(slice_object=s) + self.__print_slices(slices=slices, format=format) else: print("Status: {}".format(error.get_status())) except Exception as e: @@ -59,14 +61,13 @@ def get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str, sli print("Exception occurred while processing get_slices {}".format(e)) def get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: str, rid: str, - state: str, id_token: str, email: str): + state: str, id_token: str, email: str, site:str, type: str, format: str): try: reservations, error = self.do_get_reservations(actor_name=actor_name, callback_topic=callback_topic, slice_id=slice_id, rid=rid, state=state, id_token=id_token, - email=email) + email=email, site=site, type=type) if reservations is not None and len(reservations) > 0: - for r in reservations: - self.__print_reservation(reservation=r, detailed=(rid is not None)) + self.__print_reservations(reservations=reservations, format=format) else: print("Status: {}".format(error.get_status())) except Exception as e: @@ -75,13 +76,12 @@ def get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: st print("Exception occurred while processing get_reservations {}".format(e)) def get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: str, did: str, state: str, - id_token: str): + id_token: str, format: str): try: delegations, error = self.do_get_delegations(actor_name=actor_name, callback_topic=callback_topic, slice_id=slice_id, did=did, state=state, id_token=id_token) if delegations is not None and len(delegations) > 0: - for d in delegations: - ShowCommand.__print_delegation(dlg_object=d) + self.__print_delegations(delegations=delegations, format=format) else: print("Status: {}".format(error.get_status())) except Exception as e: @@ -110,8 +110,8 @@ def do_get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str = return None, actor.get_last_error() def do_get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: str = None, rid: str = None, - state: str = None, id_token: str = None, - email: str = None) -> Tuple[List[ReservationMng] or None, Error]: + state: str = None, id_token: str = None, email: str = None, site: str = None, + type: str = None) -> Tuple[List[ReservationMng] or None, Error]: actor = self.get_actor(actor_name=actor_name) if actor is None: @@ -123,8 +123,8 @@ def do_get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: reservation_state = None if state is not None and state != "all": reservation_state = ReservationStates.translate(state_name=state).value - return actor.get_reservations(slice_id=sid, rid=reservation_id, - state=reservation_state, email=email), actor.get_last_error() + return actor.get_reservations(slice_id=sid, rid=reservation_id, state=reservation_state, email=email, + site=site, type=type), actor.get_last_error() except Exception as e: ex_str = traceback.format_exc() self.logger.error(ex_str) @@ -153,7 +153,54 @@ def do_get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: return None, actor.get_last_error() @staticmethod - def __print_reservation(*, reservation: ReservationMng, detailed: bool = False): + def __print_reservations_json(*, reservations: List[ReservationMng]): + res_list = [] + for reservation in reservations: + res_dict = { + 'sliver_id': reservation.reservation_id, + 'slice_id': reservation.slice_id + } + if reservation.rtype is not None: + res_dict['type'] = reservation.rtype + + if reservation.rtype is not None: + res_dict['notices'] = reservation.notices + + if reservation.start is not None: + res_dict['start'] = ShowCommand.__time_string(milliseconds=reservation.start) + + if reservation.end is not None: + res_dict['end'] = ShowCommand.__time_string(milliseconds=reservation.end) + + if reservation.requested_end is not None: + res_dict['requested_end'] = ShowCommand.__time_string(milliseconds=reservation.requested_end) + + if reservation.units is not None: + res_dict['units'] = reservation.units + + if reservation.state is not None: + res_dict['state'] = reservation.state + + if reservation.pending_state is not None: + res_dict['pending_state'] = reservation.pending_state + + sliver = reservation.get_sliver() + if sliver is not None: + res_dict['sliver'] = ABCPropertyGraph.sliver_to_dict(sliver) + + res_list.append(res_dict) + + print(json.dumps(res_list, indent=4)) + + def __print_reservations(self, reservations: List[ReservationMng], format: str): + if format == 'text': + for r in reservations: + self.__print_reservation(reservation=r) + else: + self.__print_reservations_json(reservations=reservations) + + @staticmethod + def __print_reservation(*, reservation: ReservationMng): """ Prints ReservationMng """ @@ -173,12 +220,7 @@ def __print_reservation(*, reservation: ReservationMng, detailed: bool = False): sliver = reservation.get_sliver() if sliver is not None: - print(f"Sliver: {sliver}") - if detailed: - if isinstance(sliver, NodeSliver): - ShowCommand.__print_node_sliver(sliver=sliver) - elif isinstance(sliver, NetworkServiceSliver): - ShowCommand.__print_ns_sliver(sliver=sliver) + print(f"Sliver: {sliver_to_str(sliver=sliver)}") print("") @staticmethod @@ -219,6 +261,33 @@ def __print_slice(*, slice_object: SliceAvro): print(f"Lease time: {slice_object.get_lease_end()}") print("") + @staticmethod + def __print_slice_json(*, slices: List[SliceAvro]): + """ + Prints Slice Object + """ + slc_list = [] + for slice_object in slices: + slc_dict = {'name': slice_object.get_slice_name(), + 'slice_id': slice_object.get_slice_id(), + 'project_id': slice_object.get_project_id(), + 'graph_id': slice_object.get_graph_id(), + 'owner': slice_object.get_owner().get_email(), + 'state': str(SliceState(slice_object.get_state())), + 'lease_start_time': str(slice_object.get_lease_start()), + 'lease_end_time': str(slice_object.get_lease_end()) + } + slc_list.append(slc_dict) + + print(json.dumps(slc_list, indent=4)) + + def __print_slices(self, slices: List[SliceAvro], format: str): + if format == 'text': + for s in slices: + self.__print_slice(slice_object=s) + else: + self.__print_slice_json(slices=slices) + @staticmethod def __print_delegation(*, dlg_object: DelegationAvro): """ @@ -236,3 +305,27 @@ def __print_delegation(*, dlg_object: DelegationAvro): print("Graph: {}".format(dlg_object.graph)) print("") + @staticmethod + def __print_delegations_json(*, delegations: List[DelegationAvro]): + """ + Prints the Delegation Object + """ + dlg_list = [] + for dlg_object in delegations: + dlg_dict = { + 'name': dlg_object.get_name(), + 'dlg_id': dlg_object.get_delegation_id(), + 'slice_id': dlg_object.get_delegation_id(), + 'sequence': dlg_object.get_sequence(), + 'state': str(DelegationState(dlg_object.state)), + 'graph': dlg_object.graph + } + dlg_list.append(dlg_dict) + print(json.dumps(dlg_list, indent=4)) + + def __print_delegations(self, *, delegations: List[DelegationAvro], format: str): + if format == 'text': + for d in delegations: + self.__print_delegation(dlg_object=d) + else: + self.__print_delegations_json(delegations=delegations) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 71c4a95..4469f0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,5 @@ click==7.1.2 pytest==7.1.1 setuptools -urllib3==1.26.5 -six==1.15.0 -packaging==20.8 -certifi==2020.12.5 -attrs==20.3.0 -Jinja2==2.11.3 -MarkupSafe==1.1.1 -fabric-cf==1.3.1 +fabric-cf==1.4.0b7 fabric-credmgr-client==1.3.2 From 107130b44048acabbd08befa118514bee77624ff Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Sat, 3 Dec 2022 01:02:50 -0500 Subject: [PATCH 02/10] up version --- fabric_mgmt_cli/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric_mgmt_cli/__init__.py b/fabric_mgmt_cli/__init__.py index 0b0ad2a..7960a21 100644 --- a/fabric_mgmt_cli/__init__.py +++ b/fabric_mgmt_cli/__init__.py @@ -1 +1 @@ -__VERSION__ = "1.3.0" +__VERSION__ = "1.4.0b1" From ecd485c708ddcfeb009d88cb808f858923645467 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Tue, 20 Dec 2022 18:14:27 -0500 Subject: [PATCH 03/10] updates for maint mode --- README.md | 100 ++++++++++++++++++-- fabric_mgmt_cli/managecli/manage_command.py | 50 ++++++---- fabric_mgmt_cli/managecli/managecli.py | 36 ++++--- fabric_mgmt_cli/managecli/show_command.py | 31 +++--- requirements.txt | 2 +- 5 files changed, 170 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index d56d101..eb88ba7 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ peers: ## Usage Management CLI supports show and manage commands: ``` -(mgmtcli) $ fabric-mgmt-cli +$ fabric-mgmt-cli Usage: fabric-mgmt-cli [OPTIONS] COMMAND [ARGS]... Options: @@ -134,13 +134,15 @@ Options: Commands: delegations Delegation management + maintenance Maintenance Operations + net Dataplane network management slices Slice management slivers Sliver management ``` ### Delegation Commands List of the delegation commands supported can be found below: ``` -(mgmtcli) $ fabric-mgmt-cli delegations +$ fabric-mgmt-cli delegations Usage: fabric-mgmt-cli delegations [OPTIONS] COMMAND [ARGS]... Delegation management @@ -150,13 +152,15 @@ Options: Commands: claim Claim delegation(s) from AM to Broker + close Closes delegation for an actor query Get delegation(s) from an actor reclaim Reclaim delegation(s) from Broker to AM + remove Removes sliver for an actor ``` ### Slice Commands List of the Slice commands supported can be found below: ``` -(mgmtcli) $ fabric-mgmt-cli slices +$ fabric-mgmt-cli slices Usage: fabric-mgmt-cli slices [OPTIONS] COMMAND [ARGS]... Slice management @@ -165,14 +169,15 @@ Options: --help Show this message and exit. Commands: - close Closes slice for an actor - query Get slice(s) from an actor - remove Removes slice for an actor + close Closes slice for an actor + query Get slice(s) from an actor + remove Removes slice for an actor + removealldead Removes slice for an actor ``` ### Sliver Commands List of the Sliver commands supported can be found below: ``` -(mgmtcli) $ fabric-mgmt-cli slivers +$ fabric-mgmt-cli slivers Usage: fabric-mgmt-cli slivers [OPTIONS] COMMAND [ARGS]... Sliver management @@ -184,4 +189,85 @@ Commands: close Closes sliver for an actor query Get sliver(s) from an actor remove Removes sliver for an actor +``` + +### Maintenance Commands +List of the Maintenance commands supported can be found below: +``` +$ fabric-mgmt-cli maintenance +Usage: fabric-mgmt-cli maintenance [OPTIONS] COMMAND [ARGS]... + + Maintenance Operations + +Options: + --help Show this message and exit. + +Commands: + site Change Maintenance modes (PreMaint, Maint, Active) for a + specific... + + testbed Change Maintenance modes (PreMaint, Maint, Active) for the... +``` + +#### Examples +NOTE: Specific projects/users can still be allowed to provision by passing: +- Comma separated list of email addresses of the allowed users in the argument `--users` +- Command separated list of the allowed project ids in the argument `--projects` +##### Change Testbed Maintenance Mode +Move Testbed in Pre-Maintenance Mode. +``` +$ fabric-mgmt-cli maintenance testbed --actor orchestrator --mode PreMaint --deadline '2022-12-26T22:29:51.214418+00:00' --end '2022-12-30T22:29:51.214418+00:00' +``` +Move Testbed in Maintenance Mode. +``` +$ fabric-mgmt-cli maintenance testbed --actor orchestrator --mode Maint +``` +Move Testbed in Active Mode +``` +$ fabric-mgmt-cli maintenance testbed --actor orchestrator --mode Active +``` +##### Change Site Maintenance Mode +Move Site in Pre-Maintenance Mode. +``` +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode PreMaint --deadline '2022-12-26T22:29:51.214418+00:00' --end '2022-12-30T22:29:51.214418+00:00' +``` +Move Site in Maintenance Mode. +``` +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Maint +``` +Move Site in Active Mode +``` +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Active +``` + +##### Change Worker Maintenance Mode +Move Worker in Pre-Maintenance Mode. +``` +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode PreMaint --deadline '2022-12-26T22:29:51.214418+00:00' --end '2022-12-30T22:29:51.214418+00:00' --workers renc-w1.fabric-testbed.net +``` +Move Worker in Maintenance Mode. +``` +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Maint +``` +Move Worker in Active Mode +``` +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Active +``` + +### Network Management Commands +List of the Network Management commands supported can be found below: +``` +$ fabric-mgmt-cli net +Usage: fabric-mgmt-cli net [OPTIONS] COMMAND [ARGS]... + + Dataplane network management + +Options: + --help Show this message and exit. + +Commands: + create Create a new network service + delete Delete an existing network service by name + show Subgroup for network information commands + sync Control NSO device synchronization ``` \ No newline at end of file diff --git a/fabric_mgmt_cli/managecli/manage_command.py b/fabric_mgmt_cli/managecli/manage_command.py index f99532e..79aca02 100644 --- a/fabric_mgmt_cli/managecli/manage_command.py +++ b/fabric_mgmt_cli/managecli/manage_command.py @@ -29,13 +29,13 @@ from fabric_cf.actor.core.apis.abc_delegation import DelegationState from fabric_cf.actor.core.common.constants import Constants -from fabric_cf.actor.core.container.maintenance import MaintenanceState from fabric_cf.actor.core.kernel.slice_state_machine import SliceState from fabric_cf.actor.core.manage.error import Error from fabric_cf.actor.core.util.id import ID from fabric_mb.message_bus.messages.delegation_avro import DelegationAvro from fabric_mb.message_bus.messages.site_avro import SiteAvro from fabric_mb.message_bus.messages.slice_avro import SliceAvro +from fim.slivers.maintenance_mode import MaintenanceInfo, MaintenanceEntry, MaintenanceState from fabric_mgmt_cli.managecli.show_command import ShowCommand @@ -365,19 +365,20 @@ def reclaim_delegations(self, *, broker: str, am: str, callback_topic: str, did: self.logger.error(f"Exception occurred e: {e}") self.logger.error(traceback.format_exc()) - def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, mode: str, projects: str = None, + def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, state: str, projects: str = None, users: str = None, site_name: str = None, workers: str = None, deadline: str = None, - id_token: str = None): + expected_end: str = None, id_token: str = None): """ Claim delegations @param actor_name actor name @param callback_topic callback topic - @param mode mode + @param state Maintenance State @param projects comma separated list of project_ids allowed in maintenance @param users comma separated list of email address of the users allowed in maintenance @param site_name site name @param workers comma separated list of specific workers on a site which are in maintenance @param deadline start time for the Maintenance + @param expected_end Expected End time for the Maintenance @param id_token id token """ status = False @@ -388,31 +389,48 @@ def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, mode: if actor is None: raise Exception(f"Invalid arguments! {actor_name} not found") - mode = MaintenanceState.translate_string_to_state(state_string=mode.lower()) - mode_value = mode.value + mode = MaintenanceState.from_string(state) if mode == MaintenanceState.PreMaint and deadline is None: raise Exception("Required parameter: deadline is missing!") if deadline is not None: try: - maint_start_time = datetime.strptime(deadline, Constants.LEASE_TIME_FORMAT) + maint_start_time = datetime.fromisoformat(deadline) except Exception as e: - raise Exception(f"Deadline is not in format {Constants.LEASE_TIME_FORMAT}") + raise Exception(f"Deadline is not in ISO 8601 format") now = datetime.now(timezone.utc) if maint_start_time < now: raise Exception(f"Deadline cannot be before current time {now}") + if expected_end is not None: + try: + expected_end_time = datetime.fromisoformat(deadline) + except Exception as e: + raise Exception(f"Expected end is not in ISO 8601 format") + now = datetime.now(timezone.utc) + if expected_end_time < now: + raise Exception(f"Expected end cannot be before current time {now}") + try: actor.prepare(callback_topic=callback_topic) sites = None - if site_name is not None: - site_avro = SiteAvro(name=site_name, state=mode_value, workers=workers, deadline=deadline) - sites = [site_avro] - mode_value = None + if site_name is None: + site_name = Constants.ALL + + worker_list = [site_name] + if workers is not None: + worker_list = workers.split(",") + + maint_info = MaintenanceInfo() + for w in worker_list: + entry = MaintenanceEntry(state=state, deadline=deadline, expected_end=expected_end) + maint_info.add(w, entry) + site_avro = SiteAvro(name=site_name, maint_info=maint_info) + sites = [site_avro] - status = actor.toggle_maintenance_mode(actor_guid=str(actor.get_guid()), mode=mode_value, sites=sites, - projects=projects, users=users, callback_topic=callback_topic) + status = actor.toggle_maintenance_mode(actor_guid=str(actor.get_guid()), sites=sites, projects=projects, + users=users, callback_topic=callback_topic) except Exception as e: self.logger.error(f"Exception occurred e: {e}") @@ -425,9 +443,9 @@ def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, mode: error = str(e) if status: - print(f"Maintenance mode successfully set to {mode}") + print(f"Maintenance mode successfully set to {state}") else: - print(f"Failure to set maintenance mode: [{mode}]; Error: [{error}]") + print(f"Failure to set maintenance mode: [{state}]; Error: [{error}]") def delete_dead_slices(self, *, actor_name: str, callback_topic: str, id_token: str, email: str): diff --git a/fabric_mgmt_cli/managecli/managecli.py b/fabric_mgmt_cli/managecli/managecli.py index 95caad3..821f649 100644 --- a/fabric_mgmt_cli/managecli/managecli.py +++ b/fabric_mgmt_cli/managecli/managecli.py @@ -230,8 +230,9 @@ def remove(ctx, sliverid, actor, idtoken, refreshtoken): 'L3VPN]', required=False) @click.option('--format', default='text', help='Output Format Type: text or json', required=False) +@click.option('--fields', default='text', help='Comma separated list of fields to be displayed', required=False) @click.pass_context -def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email, site, type, format): +def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email, site, type, format, fields): """ Get sliver(s) from an actor """ try: @@ -240,7 +241,7 @@ def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email, si mgmt_command.get_reservations(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), slice_id=sliceid, rid=sliverid, state=state, id_token=idtoken, email=email, - site=site, type=type, format=format) + site=site, type=type, format=format, fields=fields) KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() @@ -386,23 +387,32 @@ def maintenance(ctx): @maintenance.command() @click.option('--actor', help='Actor Name', required=True) -@click.option('--mode', help='Mode value, i.e. PreMaint, Maint, NoMaint', required=True) +@click.option('--mode', help='Mode value, i.e. PreMaint, Maint, Active', required=True) @click.option('--projects', help='Comma separated list of Project Ids allowed to use TestBed in Maintenance mode', required=False, default=None) @click.option('--users', help='Comma separated list of User emails allowed to use TestBed in Maintenance mode', required=False, default=None) +@click.option('--deadline', + help='Start time that allows new resources to be created or extended up ' + 'until stated deadline in format: %Y-%m-%d %H:%M:%S %z', + required=False, default=None) +@click.option('--end', + help='Expected End for the Maintainenance in formt: %Y-%m-%d %H:%M:%S %z', + required=False, default=None) @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @click.pass_context -def testbed(ctx, actor: str, mode: str, projects: str, users: str, idtoken: str, refreshtoken: str): - """ Change Maintenance modes (PreMaint, Maint, NoMaint) for the Testbed +def testbed(ctx, actor: str, mode: str, projects: str, users: str, deadline: str, end: str, idtoken: str, + refreshtoken: str): + """ Change Maintenance modes (PreMaint, Maint, Active) for the Testbed """ try: idtoken = KafkaProcessorSingleton.get().start(id_token=idtoken, refresh_token=refreshtoken, ignore_tokens=True) mgmt_command = ManageCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.toggle_maintenance_mode(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - mode=mode, projects=projects, users=users, id_token=idtoken) + state=mode, projects=projects, users=users, id_token=idtoken, + deadline=deadline, expected_end=end) KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() @@ -412,7 +422,7 @@ def testbed(ctx, actor: str, mode: str, projects: str, users: str, idtoken: str, @maintenance.command() @click.option('--actor', help='Actor Name', required=True) @click.option('--name', help='Site Name', required=True) -@click.option('--mode', help='Mode value, i.e. PreMaint, Maint, NoMaint', required=True) +@click.option('--mode', help='Mode value, i.e. PreMaint, Maint, Active', required=True) @click.option('--projects', help='Comma separated list of Project Ids allowed to use TestBed in Maintenance mode', required=False, default=None) @click.option('--users', help='Comma separated list of User emails allowed to use TestBed in Maintenance mode', @@ -420,21 +430,25 @@ def testbed(ctx, actor: str, mode: str, projects: str, users: str, idtoken: str, @click.option('--workers', help='Comma separated list of workers to be marked in Maintenance mode', required=False, default=None) @click.option('--deadline', - help='Start time that allows new resources to be created or extended up until stated deadline in format: %Y-%m-%d %H:%M:%S %z', + help='Start time that allows new resources to be created or extended up ' + 'until stated deadline in format: %Y-%m-%d %H:%M:%S %z', + required=False, default=None) +@click.option('--end', + help='Expected End for the Maintainenance in formt: %Y-%m-%d %H:%M:%S %z', required=False, default=None) @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @click.pass_context -def site(ctx, actor: str, name: str, mode: str, projects, users, workers: str, deadline: str, +def site(ctx, actor: str, name: str, mode: str, projects, users, workers: str, deadline: str, end: str, idtoken: str, refreshtoken: str): - """ Change Maintenance modes (PreMaint, Maint, NoMaint) for a specific Site or a specific worker + """ Change Maintenance modes (PreMaint, Maint, Active) for a specific Site or a specific worker """ try: idtoken = KafkaProcessorSingleton.get().start(id_token=idtoken, refresh_token=refreshtoken, ignore_tokens=True) mgmt_command = ManageCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.toggle_maintenance_mode(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - mode=mode, projects=projects, users=users, + state=mode, projects=projects, users=users, expected_end=end, site_name=name, workers=workers, deadline=deadline, id_token=idtoken) KafkaProcessorSingleton.get().stop() diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index b4750fc..1412450 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -61,13 +61,13 @@ def get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str, sli print("Exception occurred while processing get_slices {}".format(e)) def get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: str, rid: str, - state: str, id_token: str, email: str, site:str, type: str, format: str): + state: str, id_token: str, email: str, site:str, type: str, format: str, fields: str): try: reservations, error = self.do_get_reservations(actor_name=actor_name, callback_topic=callback_topic, slice_id=slice_id, rid=rid, state=state, id_token=id_token, email=email, site=site, type=type) if reservations is not None and len(reservations) > 0: - self.__print_reservations(reservations=reservations, format=format) + self.__print_reservations(reservations=reservations, format=format, fields=fields) else: print("Status: {}".format(error.get_status())) except Exception as e: @@ -153,51 +153,54 @@ def do_get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: return None, actor.get_last_error() @staticmethod - def __print_reservations_json(*, reservations: List[ReservationMng]): + def __print_reservations_json(*, reservations: List[ReservationMng], fields: str): res_list = [] + field_list = None + if fields is not None: + field_list = fields.split(",") for reservation in reservations: res_dict = { 'sliver_id': reservation.reservation_id, 'slice_id': reservation.slice_id } - if reservation.rtype is not None: + if reservation.rtype is not None and (field_list is None or 'type' in field_list): res_dict['type'] = reservation.rtype - if reservation.rtype is not None: + if reservation.rtype is not None and (field_list is None or 'notices' in field_list): res_dict['notices'] = reservation.notices - if reservation.start is not None: + if reservation.start is not None and (field_list is None or 'start' in field_list): res_dict['start'] = ShowCommand.__time_string(milliseconds=reservation.start) - if reservation.end is not None: + if reservation.end is not None and (field_list is None or 'end' in field_list): res_dict['end'] = ShowCommand.__time_string(milliseconds=reservation.end) - if reservation.requested_end is not None: + if reservation.requested_end is not None and (field_list is None or 'requested_end' in field_list): res_dict['requested_end'] = ShowCommand.__time_string(milliseconds=reservation.requested_end) - if reservation.units is not None: + if reservation.units is not None and (field_list is None or 'units' in field_list): res_dict['units'] = reservation.units - if reservation.state is not None: + if reservation.state is not None and (field_list is None or 'state' in field_list): res_dict['state'] = reservation.state - if reservation.pending_state is not None: + if reservation.pending_state is not None and (field_list is None or 'pending_state' in field_list): res_dict['pending_state'] = reservation.pending_state sliver = reservation.get_sliver() - if sliver is not None: + if sliver is not None and (field_list is None or 'sliver' in field_list): res_dict['sliver'] = ABCPropertyGraph.sliver_to_dict(sliver) res_list.append(res_dict) print(json.dumps(res_list, indent=4)) - def __print_reservations(self, reservations: List[ReservationMng], format: str): + def __print_reservations(self, reservations: List[ReservationMng], format: str, fields: str): if format == 'text': for r in reservations: self.__print_reservation(reservation=r) else: - self.__print_reservations_json(reservations=reservations) + self.__print_reservations_json(reservations=reservations, fields=fields) @staticmethod def __print_reservation(*, reservation: ReservationMng): diff --git a/requirements.txt b/requirements.txt index 4469f0f..a138f36 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ click==7.1.2 pytest==7.1.1 setuptools -fabric-cf==1.4.0b7 +fabric-cf==1.4.0b9 fabric-credmgr-client==1.3.2 From dafe7b6ebbc9db40da069748eea7ceef9b521588 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Tue, 20 Dec 2022 18:24:35 -0500 Subject: [PATCH 04/10] filtering based on fields --- fabric_mgmt_cli/managecli/managecli.py | 2 +- fabric_mgmt_cli/managecli/show_command.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fabric_mgmt_cli/managecli/managecli.py b/fabric_mgmt_cli/managecli/managecli.py index 821f649..1b522ea 100644 --- a/fabric_mgmt_cli/managecli/managecli.py +++ b/fabric_mgmt_cli/managecli/managecli.py @@ -230,7 +230,7 @@ def remove(ctx, sliverid, actor, idtoken, refreshtoken): 'L3VPN]', required=False) @click.option('--format', default='text', help='Output Format Type: text or json', required=False) -@click.option('--fields', default='text', help='Comma separated list of fields to be displayed', required=False) +@click.option('--fields', default=None, help='Comma separated list of fields to be displayed', required=False) @click.pass_context def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email, site, type, format, fields): """ Get sliver(s) from an actor diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index 1412450..49be636 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -155,9 +155,10 @@ def do_get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: @staticmethod def __print_reservations_json(*, reservations: List[ReservationMng], fields: str): res_list = [] - field_list = None if fields is not None: field_list = fields.split(",") + else: + field_list = None for reservation in reservations: res_dict = { 'sliver_id': reservation.reservation_id, From dd2efb7d604a92577a0339642e4c25728d59ab6e Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Fri, 13 Jan 2023 17:37:27 -0500 Subject: [PATCH 05/10] changes to query for slivers with multiple states --- fabric_mgmt_cli/__init__.py | 2 +- fabric_mgmt_cli/managecli/manage_command.py | 2 +- fabric_mgmt_cli/managecli/managecli.py | 41 +++++++++++++++------ fabric_mgmt_cli/managecli/show_command.py | 30 +++++++++------ requirements.txt | 2 +- 5 files changed, 51 insertions(+), 26 deletions(-) diff --git a/fabric_mgmt_cli/__init__.py b/fabric_mgmt_cli/__init__.py index 7960a21..71232f6 100644 --- a/fabric_mgmt_cli/__init__.py +++ b/fabric_mgmt_cli/__init__.py @@ -1 +1 @@ -__VERSION__ = "1.4.0b1" +__VERSION__ = "1.4.0b2" diff --git a/fabric_mgmt_cli/managecli/manage_command.py b/fabric_mgmt_cli/managecli/manage_command.py index 79aca02..405151c 100644 --- a/fabric_mgmt_cli/managecli/manage_command.py +++ b/fabric_mgmt_cli/managecli/manage_command.py @@ -369,7 +369,7 @@ def toggle_maintenance_mode(self, *, actor_name: str, callback_topic: str, state users: str = None, site_name: str = None, workers: str = None, deadline: str = None, expected_end: str = None, id_token: str = None): """ - Claim delegations + Toggle Maintenance Mode @param actor_name actor name @param callback_topic callback topic @param state Maintenance State diff --git a/fabric_mgmt_cli/managecli/managecli.py b/fabric_mgmt_cli/managecli/managecli.py index 1b522ea..95d763d 100644 --- a/fabric_mgmt_cli/managecli/managecli.py +++ b/fabric_mgmt_cli/managecli/managecli.py @@ -120,20 +120,19 @@ def removealldead(ctx, email, actor, idtoken, refreshtoken): @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @click.option('--email', default=None, help='User email', required=False) -@click.option('--state', - type=click.Choice(['nascent', 'configuring', 'stableok', 'stableerror', 'modifyok', 'modifyerror', - 'closing', 'dead'], - case_sensitive=False), required=False) +@click.option('--states', help="Comma separated list of the states, possible values: " + "[nascent, configuring, stableok, stableerror, modifyok, modifyerror, closing, dead]", + required=False) @click.option('--format', default='text', help='Output Format Type: text or json', required=False) @click.pass_context -def query(ctx, actor, sliceid, slicename, idtoken, refreshtoken, email, state, format): +def query(ctx, actor, sliceid, slicename, idtoken, refreshtoken, email, states, format): """ Get slice(s) from an actor """ try: idtoken = KafkaProcessorSingleton.get().start(id_token=idtoken, refresh_token=refreshtoken, ignore_tokens=True) mgmt_command = ShowCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.get_slices(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - slice_id=sliceid, slice_name=slicename, id_token=idtoken, email=email, state=state, + slice_id=sliceid, slice_name=slicename, id_token=idtoken, email=email, states=states, format=format) KafkaProcessorSingleton.get().stop() except Exception as e: @@ -215,10 +214,8 @@ def remove(ctx, sliverid, actor, idtoken, refreshtoken): @click.option('--actor', help='Actor Name', required=True) @click.option('--sliceid', default=None, help='Slice Id', required=False) @click.option('--sliverid', default=None, help='Sliver Id', required=False) -@click.option('--state', - type=click.Choice(['nascent', 'ticketed', 'active', 'activeticketed', 'closed', 'closewait', 'failed', - 'unknown', 'all'], - case_sensitive=False), +@click.option('--states', "Comma separated list of states, possible values: " + "[nascent, ticketed, active, activeticketed, closed, closewait, failed, unknown, all]", default='all', help='Sliver State', required=False) @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @@ -232,7 +229,7 @@ def remove(ctx, sliverid, actor, idtoken, refreshtoken): @click.option('--format', default='text', help='Output Format Type: text or json', required=False) @click.option('--fields', default=None, help='Comma separated list of fields to be displayed', required=False) @click.pass_context -def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email, site, type, format, fields): +def query(ctx, actor, sliceid, sliverid, states, idtoken, refreshtoken, email, site, type, format, fields): """ Get sliver(s) from an actor """ try: @@ -240,7 +237,7 @@ def query(ctx, actor, sliceid, sliverid, state, idtoken, refreshtoken, email, si mgmt_command = ShowCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.get_reservations(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - slice_id=sliceid, rid=sliverid, state=state, id_token=idtoken, email=email, + slice_id=sliceid, rid=sliverid, states=states, id_token=idtoken, email=email, site=site, type=type, format=format, fields=fields) KafkaProcessorSingleton.get().stop() except Exception as e: @@ -455,7 +452,27 @@ def site(ctx, actor: str, name: str, mode: str, projects, users, workers: str, d except Exception as e: # traceback.print_exc() click.echo('Error occurred: {}'.format(e)) +''' + +@maintenance.command() +@click.option('--actor', help='Actor Name', required=True) +@click.option('--site', help='Site Name', required=False) +@click.pass_context +def query(ctx, actor: str, site: str): + """ Query Maintenance Status for Testbed/Site + """ + try: + idtoken = KafkaProcessorSingleton.get().start(ignore_tokens=True) + mgmt_command = ManageCommand(logger=KafkaProcessorSingleton.get().logger) + mgmt_command.get_maintenance_mode(actor_name=actor, + callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), + site=site) + KafkaProcessorSingleton.get().stop() + except Exception as e: + # traceback.print_exc() + click.echo('Error occurred: {}'.format(e)) +''' managecli.add_command(slices) managecli.add_command(slivers) diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index 49be636..11cfc09 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -47,10 +47,10 @@ class ShowCommand(Command): def get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str, slice_name: str, id_token: str, - email: str, state: str, format: str): + email: str, states: str, format: str): try: slices, error = self.do_get_slices(actor_name=actor_name, callback_topic=callback_topic, slice_id=slice_id, - slice_name=slice_name, id_token=id_token, email=email, state=state) + slice_name=slice_name, id_token=id_token, email=email, states=states) if slices is not None and len(slices) > 0: self.__print_slices(slices=slices, format=format) else: @@ -61,10 +61,10 @@ def get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str, sli print("Exception occurred while processing get_slices {}".format(e)) def get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: str, rid: str, - state: str, id_token: str, email: str, site:str, type: str, format: str, fields: str): + states: str, id_token: str, email: str, site:str, type: str, format: str, fields: str): try: reservations, error = self.do_get_reservations(actor_name=actor_name, callback_topic=callback_topic, - slice_id=slice_id, rid=rid, state=state, id_token=id_token, + slice_id=slice_id, rid=rid, states=states, id_token=id_token, email=email, site=site, type=type) if reservations is not None and len(reservations) > 0: self.__print_reservations(reservations=reservations, format=format, fields=fields) @@ -90,7 +90,7 @@ def get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: str print("Exception occurred while processing get_delegations {}".format(e)) def do_get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str = None, slice_name: str = None, - id_token: str = None, email: str = None, state: str = None) -> Tuple[List[SliceAvro] or None, Error]: + id_token: str = None, email: str = None, states: str = None) -> Tuple[List[SliceAvro] or None, Error]: actor = self.get_actor(actor_name=actor_name) if actor is None: @@ -99,8 +99,12 @@ def do_get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str = actor.prepare(callback_topic=callback_topic) sid = ID(uid=slice_id) if slice_id is not None else None slice_state = None - if state is not None: - slice_state = [SliceState.translate(state_name=state).value] + if states is not None: + states_list = states.split(",") + for x in states_list: + if slice_state is None: + slice_state = [] + slice_state.append(SliceState.translate(state_name=x).value) result = actor.get_slices(slice_id=sid, slice_name=slice_name, email=email, state=slice_state) return result, actor.get_last_error() @@ -110,7 +114,7 @@ def do_get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str = return None, actor.get_last_error() def do_get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: str = None, rid: str = None, - state: str = None, id_token: str = None, email: str = None, site: str = None, + states: str = None, id_token: str = None, email: str = None, site: str = None, type: str = None) -> Tuple[List[ReservationMng] or None, Error]: actor = self.get_actor(actor_name=actor_name) @@ -121,9 +125,13 @@ def do_get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: sid = ID(uid=slice_id) if slice_id is not None else None reservation_id = ID(uid=rid) if rid is not None else None reservation_state = None - if state is not None and state != "all": - reservation_state = ReservationStates.translate(state_name=state).value - return actor.get_reservations(slice_id=sid, rid=reservation_id, state=reservation_state, email=email, + if states is not None and states != "all": + states_list = states.split(",") + for x in states_list: + if reservation_state is not None: + reservation_state = [] + reservation_state.append(ReservationStates.translate(state_name=x).value) + return actor.get_reservations(slice_id=sid, rid=reservation_id, states=reservation_state, email=email, site=site, type=type), actor.get_last_error() except Exception as e: ex_str = traceback.format_exc() diff --git a/requirements.txt b/requirements.txt index a138f36..136970f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ click==7.1.2 pytest==7.1.1 setuptools -fabric-cf==1.4.0b9 +fabric-cf==1.4.0b12 fabric-credmgr-client==1.3.2 From 7d0043ee63a86ec2ea3958ada30f6a8173046006 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Fri, 13 Jan 2023 21:15:09 -0500 Subject: [PATCH 06/10] fixes for states --- fabric_mgmt_cli/__init__.py | 2 +- fabric_mgmt_cli/managecli/managecli.py | 20 ++++++------ fabric_mgmt_cli/managecli/show_command.py | 39 ++++++++++++----------- requirements.txt | 2 +- 4 files changed, 33 insertions(+), 30 deletions(-) diff --git a/fabric_mgmt_cli/__init__.py b/fabric_mgmt_cli/__init__.py index 71232f6..6ef354e 100644 --- a/fabric_mgmt_cli/__init__.py +++ b/fabric_mgmt_cli/__init__.py @@ -1 +1 @@ -__VERSION__ = "1.4.0b2" +__VERSION__ = "1.4.0b4" diff --git a/fabric_mgmt_cli/managecli/managecli.py b/fabric_mgmt_cli/managecli/managecli.py index 95d763d..c5ff204 100644 --- a/fabric_mgmt_cli/managecli/managecli.py +++ b/fabric_mgmt_cli/managecli/managecli.py @@ -122,7 +122,7 @@ def removealldead(ctx, email, actor, idtoken, refreshtoken): @click.option('--email', default=None, help='User email', required=False) @click.option('--states', help="Comma separated list of the states, possible values: " "[nascent, configuring, stableok, stableerror, modifyok, modifyerror, closing, dead]", - required=False) + default=None, required=False) @click.option('--format', default='text', help='Output Format Type: text or json', required=False) @click.pass_context def query(ctx, actor, sliceid, slicename, idtoken, refreshtoken, email, states, format): @@ -214,9 +214,9 @@ def remove(ctx, sliverid, actor, idtoken, refreshtoken): @click.option('--actor', help='Actor Name', required=True) @click.option('--sliceid', default=None, help='Slice Id', required=False) @click.option('--sliverid', default=None, help='Sliver Id', required=False) -@click.option('--states', "Comma separated list of states, possible values: " - "[nascent, ticketed, active, activeticketed, closed, closewait, failed, unknown, all]", - default='all', help='Sliver State', required=False) +@click.option('--states', default=None, help='Sliver State, Comma separated list of states, possible values: ' + '[nascent, ticketed, active, activeticketed, closed, closewait, ' + 'failed, unknown, all]', required=False) @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @click.option('--email', default=None, help='User Email', required=False) @@ -305,15 +305,15 @@ def reclaim(ctx, broker: str, am: str, did: str, idtoken, refreshtoken): @click.option('--actor', help='Actor Name', required=True) @click.option('--sliceid', default=None, help='Slice Id', required=False) @click.option('--did', default=None, help='Delegation Id', required=False) -@click.option('--state', - type=click.Choice(['nascent', 'delegated', 'reclaimed', 'closed', 'failed', 'all'], - case_sensitive=False), - default='all', help='Sliver State', required=False) +@click.option('--states', + default=None, help="Comma separated list of the states, possible values: " + "[nascent, delegated, reclaimed, failed, closed]", + required=False) @click.option('--idtoken', default=None, help='Fabric Identity Token', required=False) @click.option('--refreshtoken', default=None, help='Fabric Refresh Token', required=False) @click.option('--format', default='text', help='Output Format Type: text or json', required=False) @click.pass_context -def query(ctx, actor, sliceid, did, state, idtoken, refreshtoken, format): +def query(ctx, actor, sliceid, did, states, idtoken, refreshtoken, format): """ Get delegation(s) from an actor """ try: @@ -321,7 +321,7 @@ def query(ctx, actor, sliceid, did, state, idtoken, refreshtoken, format): mgmt_command = ShowCommand(logger=KafkaProcessorSingleton.get().logger) mgmt_command.get_delegations(actor_name=actor, callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - slice_id=sliceid, did=did, state=state, id_token=idtoken, format=format) + slice_id=sliceid, did=did, states=states, id_token=idtoken, format=format) KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index 11cfc09..2d897b2 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -75,11 +75,11 @@ def get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: st self.logger.error(ex_str) print("Exception occurred while processing get_reservations {}".format(e)) - def get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: str, did: str, state: str, + def get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: str, did: str, states: str, id_token: str, format: str): try: delegations, error = self.do_get_delegations(actor_name=actor_name, callback_topic=callback_topic, - slice_id=slice_id, did=did, state=state, id_token=id_token) + slice_id=slice_id, did=did, states=states, id_token=id_token) if delegations is not None and len(delegations) > 0: self.__print_delegations(delegations=delegations, format=format) else: @@ -98,15 +98,15 @@ def do_get_slices(self, *, actor_name: str, callback_topic: str, slice_id: str = try: actor.prepare(callback_topic=callback_topic) sid = ID(uid=slice_id) if slice_id is not None else None - slice_state = None + slice_states = None if states is not None: states_list = states.split(",") for x in states_list: - if slice_state is None: - slice_state = [] - slice_state.append(SliceState.translate(state_name=x).value) + if slice_states is None: + slice_states = [] + slice_states.append(SliceState.translate(state_name=x).value) - result = actor.get_slices(slice_id=sid, slice_name=slice_name, email=email, state=slice_state) + result = actor.get_slices(slice_id=sid, slice_name=slice_name, email=email, states=slice_states) return result, actor.get_last_error() except Exception: ex_str = traceback.format_exc() @@ -124,14 +124,14 @@ def do_get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: actor.prepare(callback_topic=callback_topic) sid = ID(uid=slice_id) if slice_id is not None else None reservation_id = ID(uid=rid) if rid is not None else None - reservation_state = None - if states is not None and states != "all": + reservation_states = None + if states is not None: states_list = states.split(",") for x in states_list: - if reservation_state is not None: - reservation_state = [] - reservation_state.append(ReservationStates.translate(state_name=x).value) - return actor.get_reservations(slice_id=sid, rid=reservation_id, states=reservation_state, email=email, + if reservation_states is not None: + reservation_states = [] + reservation_states.append(ReservationStates.translate(state_name=x).value) + return actor.get_reservations(slice_id=sid, rid=reservation_id, states=reservation_states, email=email, site=site, type=type), actor.get_last_error() except Exception as e: ex_str = traceback.format_exc() @@ -139,7 +139,7 @@ def do_get_reservations(self, *, actor_name: str, callback_topic: str, slice_id: return None, actor.get_last_error() def do_get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: str = None, did: str = None, - state: str = None, id_token: str = None) -> Tuple[List[DelegationAvro] or None, Error]: + states: str = None, id_token: str = None) -> Tuple[List[DelegationAvro] or None, Error]: actor = self.get_actor(actor_name=actor_name) if actor is None: @@ -149,11 +149,14 @@ def do_get_delegations(self, *, actor_name: str, callback_topic: str, slice_id: sid = None if slice_id is not None: sid = ID(uid=slice_id) - delegation_state = None - if state is not None and state != "all": - delegation_state = DelegationState.translate(state_name=state).value + delegation_states = None + if states is not None: + for x in states: + if delegation_states is None: + delegation_states = [] + delegation_states.append(DelegationState.translate(state_name=x).value) return actor.get_delegations(delegation_id=did, slice_id=sid, - state=delegation_state), actor.get_last_error() + states=delegation_states), actor.get_last_error() except Exception as e: self.logger.error(f"Exception occurred while fetching delegations: e {e}") self.logger.error(traceback.format_exc()) diff --git a/requirements.txt b/requirements.txt index 136970f..0f4af29 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ click==7.1.2 pytest==7.1.1 setuptools -fabric-cf==1.4.0b12 +fabric-cf==1.4.0b14 fabric-credmgr-client==1.3.2 From 99bfe345c70b9097fb288d6f53ea72ffcbd02631 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Thu, 19 Jan 2023 14:21:46 -0500 Subject: [PATCH 07/10] get site maint info --- README.md | 4 +- fabric_mgmt_cli/__init__.py | 2 +- fabric_mgmt_cli/managecli/kafka_processor.py | 4 +- fabric_mgmt_cli/managecli/managecli.py | 15 ++++--- fabric_mgmt_cli/managecli/show_command.py | 43 +++++++++++++++++++- requirements.txt | 2 +- 6 files changed, 55 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index eb88ba7..cf6d30f 100644 --- a/README.md +++ b/README.md @@ -247,11 +247,11 @@ $ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode PreMa ``` Move Worker in Maintenance Mode. ``` -$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Maint +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Maint --workers renc-w1.fabric-testbed.net ``` Move Worker in Active Mode ``` -$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Active +$ fabric-mgmt-cli maintenance site --name RENC --actor orchestrator --mode Active --workers renc-w1.fabric-testbed.net ``` ### Network Management Commands diff --git a/fabric_mgmt_cli/__init__.py b/fabric_mgmt_cli/__init__.py index 6ef354e..8812bb9 100644 --- a/fabric_mgmt_cli/__init__.py +++ b/fabric_mgmt_cli/__init__.py @@ -1 +1 @@ -__VERSION__ = "1.4.0b4" +__VERSION__ = "1.4.0b5" diff --git a/fabric_mgmt_cli/managecli/kafka_processor.py b/fabric_mgmt_cli/managecli/kafka_processor.py index ad35f46..bab6eb0 100644 --- a/fabric_mgmt_cli/managecli/kafka_processor.py +++ b/fabric_mgmt_cli/managecli/kafka_processor.py @@ -193,7 +193,7 @@ def get_tokens(self, id_token: str, refresh_token: str) -> str: if refresh_token is not None: try: proxy = CredmgrProxy(credmgr_host=self.config_processor.get_credmgr_host()) - tokens = proxy.refresh(project_name="all", scope="all", refresh_token=refresh_token) + tokens = proxy.refresh(project_id=None, scope="all", refresh_token=refresh_token) id_token = tokens.get('id_token', None) except Exception as e: raise TokenException('Not a valid refresh_token! Error: {}'.format(e)) @@ -205,7 +205,7 @@ def get_tokens(self, id_token: str, refresh_token: str) -> str: return id_token - def start(self, id_token: str, refresh_token: str, ignore_tokens: bool = False) -> str: + def start(self, id_token: str = None, refresh_token: str = None, ignore_tokens: bool = False) -> str: """ Start Synchronous Kafka Processor @param id_token identity token diff --git a/fabric_mgmt_cli/managecli/managecli.py b/fabric_mgmt_cli/managecli/managecli.py index c5ff204..f4b6e28 100644 --- a/fabric_mgmt_cli/managecli/managecli.py +++ b/fabric_mgmt_cli/managecli/managecli.py @@ -452,27 +452,26 @@ def site(ctx, actor: str, name: str, mode: str, projects, users, workers: str, d except Exception as e: # traceback.print_exc() click.echo('Error occurred: {}'.format(e)) -''' @maintenance.command() @click.option('--actor', help='Actor Name', required=True) -@click.option('--site', help='Site Name', required=False) +@click.option('--sites', help='Site Names, Comma separated list of the site names or ALL for entire testbed', required=False) @click.pass_context -def query(ctx, actor: str, site: str): +def query(ctx, actor: str, sites: str): """ Query Maintenance Status for Testbed/Site """ try: idtoken = KafkaProcessorSingleton.get().start(ignore_tokens=True) - mgmt_command = ManageCommand(logger=KafkaProcessorSingleton.get().logger) - mgmt_command.get_maintenance_mode(actor_name=actor, - callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), - site=site) + mgmt_command = ShowCommand(logger=KafkaProcessorSingleton.get().logger) + mgmt_command.get_sites(actor_name=actor, + callback_topic=KafkaProcessorSingleton.get().get_callback_topic(), + sites=sites) KafkaProcessorSingleton.get().stop() except Exception as e: # traceback.print_exc() click.echo('Error occurred: {}'.format(e)) -''' + managecli.add_command(slices) managecli.add_command(slivers) diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index 2d897b2..056b67f 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -37,6 +37,7 @@ from fabric_cf.actor.core.util.utils import sliver_to_str from fabric_mb.message_bus.messages.delegation_avro import DelegationAvro from fabric_mb.message_bus.messages.reservation_mng import ReservationMng +from fabric_mb.message_bus.messages.site_avro import SiteAvro from fabric_mb.message_bus.messages.slice_avro import SliceAvro from fim.graph.abc_property_graph import ABCPropertyGraph from fim.slivers.network_node import NodeSliver @@ -343,4 +344,44 @@ def __print_delegations(self, *, delegations: List[DelegationAvro], format: str) for d in delegations: self.__print_delegation(dlg_object=d) else: - self.__print_delegations_json(delegations=delegations) \ No newline at end of file + self.__print_delegations_json(delegations=delegations) + + def do_get_sites(self, *, actor_name: str, callback_topic: str, sites: str) -> Tuple[List[SiteAvro] or None, Error]: + actor = self.get_actor(actor_name=actor_name) + + if actor is None: + raise Exception("Invalid arguments actor {} not found".format(actor_name)) + try: + actor.prepare(callback_topic=callback_topic) + return actor.get_sites(site=sites), actor.get_last_error() + except Exception as e: + self.logger.error(f"Exception occurred while fetching delegations: e {e}") + self.logger.error(traceback.format_exc()) + traceback.print_exc() + return None, actor.get_last_error() + + def get_sites(self, *, actor_name: str, callback_topic: str, sites:str): + try: + sites, error = self.do_get_sites(actor_name=actor_name, callback_topic=callback_topic, sites=sites) + if sites is not None and len(sites) > 0: + self.__print_sites(sites=sites, format=format) + else: + print("Status: {}".format(error.get_status())) + except Exception as e: + ex_str = traceback.format_exc() + self.logger.error(ex_str) + print("Exception occurred while processing get_delegations {}".format(e)) + + def __print_sites(self, *, sites: List[SiteAvro], format: str): + if format == 'text': + for s in sites: + print(s) + else: + site_list = [] + for s in sites: + s_dict = { + 'name': s.get_name(), + 'maint_info': s.get_maint_info().to_json() + } + site_list.append(s_dict) + print(json.dumps(site_list, indent=4)) diff --git a/requirements.txt b/requirements.txt index 0f4af29..24e410f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ click==7.1.2 pytest==7.1.1 setuptools -fabric-cf==1.4.0b14 +fabric-cf==1.4.0b17 fabric-credmgr-client==1.3.2 From a2b4f02062caecad3465f9d90f18bd7adf9bc2e4 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Fri, 20 Jan 2023 17:37:57 -0500 Subject: [PATCH 08/10] up the versions --- fabric_mgmt_cli/__init__.py | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric_mgmt_cli/__init__.py b/fabric_mgmt_cli/__init__.py index 8812bb9..b2c6a8d 100644 --- a/fabric_mgmt_cli/__init__.py +++ b/fabric_mgmt_cli/__init__.py @@ -1 +1 @@ -__VERSION__ = "1.4.0b5" +__VERSION__ = "1.4.0" diff --git a/requirements.txt b/requirements.txt index 24e410f..1020db1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ click==7.1.2 pytest==7.1.1 setuptools -fabric-cf==1.4.0b17 +fabric-cf==1.4.0 fabric-credmgr-client==1.3.2 From cee5826ba709ed5ec73491dc5f9720120b67068c Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Fri, 20 Jan 2023 17:42:00 -0500 Subject: [PATCH 09/10] fix slice_id --- fabric_mgmt_cli/managecli/show_command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index 056b67f..f682a57 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -263,7 +263,7 @@ def __print_slice(*, slice_object: SliceAvro): """ print("") print(f"Slice Name: {slice_object.get_slice_name()} Slice ID: {slice_object.get_slice_id()} " - f"Project ID: {slice_object.get_slice_id()}") + f"Project ID: {slice_object.get_project_id()}") if slice_object.get_graph_id() is not None: print(f"Graph ID: {slice_object.get_graph_id()}") From bed1c5f3b750f03a7f29edc51ef7a755b245f4f9 Mon Sep 17 00:00:00 2001 From: Komal Thareja Date: Fri, 20 Jan 2023 17:44:16 -0500 Subject: [PATCH 10/10] fix project name --- fabric_mgmt_cli/managecli/show_command.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fabric_mgmt_cli/managecli/show_command.py b/fabric_mgmt_cli/managecli/show_command.py index f682a57..8770c58 100644 --- a/fabric_mgmt_cli/managecli/show_command.py +++ b/fabric_mgmt_cli/managecli/show_command.py @@ -263,7 +263,7 @@ def __print_slice(*, slice_object: SliceAvro): """ print("") print(f"Slice Name: {slice_object.get_slice_name()} Slice ID: {slice_object.get_slice_id()} " - f"Project ID: {slice_object.get_project_id()}") + f"Project ID: {slice_object.get_project_id()} Project Name: {slice_object.get_project_name()} ") if slice_object.get_graph_id() is not None: print(f"Graph ID: {slice_object.get_graph_id()}") @@ -287,6 +287,7 @@ def __print_slice_json(*, slices: List[SliceAvro]): slc_dict = {'name': slice_object.get_slice_name(), 'slice_id': slice_object.get_slice_id(), 'project_id': slice_object.get_project_id(), + 'project_name': slice_object.get_project_name(), 'graph_id': slice_object.get_graph_id(), 'owner': slice_object.get_owner().get_email(), 'state': str(SliceState(slice_object.get_state())),