Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slice sharing #281

Merged
merged 9 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Fixed
- Reduce the time taken for the call node.get_ssh_command() (Issue [#280](https://github.com/fabric-testbed/fabrictestbed-extensions/issues/280))
- Allow access to other user's slices in a project (Issue [#279](https://github.com/fabric-testbed/fabrictestbed-extensions/issues/279))

## [1.6.3] - 2024-01-26

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion fabrictestbed_extensions/editors/abc_topology_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def create_experiment(self, slice_name):
{
"slice_name": slice_name,
"editor_slice_state": self.EXPERIMENT_STATE_UNSUBMITTED,
"topology": ExperimentTopology()
"topology": ExperimentTopology(),
# ssh_keys
# detail_levels {'detail': HIGH, {'node1': LOW, 'node2': MED}}
}
Expand Down
73 changes: 58 additions & 15 deletions fabrictestbed_extensions/fablib/fablib.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,8 @@ def get_available_resources(update: bool = False) -> Resources:

@staticmethod
def get_fim_slice(
excludes: List[SliceState] = [SliceState.Dead, SliceState.Closing]
excludes: List[SliceState] = [SliceState.Dead, SliceState.Closing],
user_only: bool = True,
) -> List[OrchestratorSlice]:
"""
Not intended for API use.
Expand All @@ -451,14 +452,20 @@ def get_fim_slice(

:param excludes: A list of slice states to exclude from the output list
:type excludes: List[SliceState]
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool

:return: a list of slices
:rtype: List[Slice]
"""
return fablib.get_default_fablib_manager().get_fim_slice(excludes=excludes)
return fablib.get_default_fablib_manager().get_fim_slice(
excludes=excludes, user_only=user_only
)

@staticmethod
def get_slices(
excludes: List[SliceState] = [SliceState.Dead, SliceState.Closing]
excludes: List[SliceState] = [SliceState.Dead, SliceState.Closing],
user_only: bool = True,
) -> List[Slice]:
"""
Gets a list of slices from the slice manager.
Expand All @@ -469,13 +476,20 @@ def get_slices(

:param excludes: A list of slice states to exclude from the output list
:type excludes: List[SliceState]
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool

:return: a list of slices
:rtype: List[Slice]
"""
return fablib.get_default_fablib_manager().get_slices(excludes=excludes)
return fablib.get_default_fablib_manager().get_slices(
excludes=excludes, user_only=user_only
)

@staticmethod
def get_slice(name: str = None, slice_id: str = None) -> Slice:
def get_slice(
name: str = None, slice_id: str = None, user_only: bool = True
) -> Slice:
"""
Gets a slice by name or slice_id. Dead and Closing slices may have
non-unique names and must be queried by slice_id. Slices in all other
Expand All @@ -488,12 +502,14 @@ def get_slice(name: str = None, slice_id: str = None) -> Slice:
:type name: String
:param slice_id: The ID of the desired slice
:type slice_id: String
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool
:raises: Exception: if slice name or slice id are not inputted
:return: the slice, if found
:rtype: Slice
"""
return fablib.get_default_fablib_manager().get_slice(
name=name, slice_id=slice_id
name=name, slice_id=slice_id, user_only=user_only
)

@staticmethod
Expand Down Expand Up @@ -1512,7 +1528,9 @@ def get_available_resources(
return self.resources

def get_fim_slices(
self, excludes: List[SliceState] = [SliceState.Dead, SliceState.Closing]
self,
excludes: List[SliceState] = [SliceState.Dead, SliceState.Closing],
user_only: bool = True,
) -> List[OrchestratorSlice]:
"""
Gets a list of fim slices from the slice manager.
Expand All @@ -1526,11 +1544,13 @@ def get_fim_slices(

:param excludes: A list of slice states to exclude from the output list
:type excludes: List[SliceState]
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool
:return: a list of fim models of slices
:rtype: List[Slice]
"""
return_status, slices = self.get_slice_manager().slices(
excludes=excludes, limit=200
excludes=excludes, limit=200, user_only=user_only
)

return_slices = []
Expand All @@ -1549,6 +1569,7 @@ def list_slices(
quiet=False,
filter_function=None,
pretty_names=True,
user_only: bool = True,
):
"""
Lists all the slices created by a user.
Expand Down Expand Up @@ -1581,10 +1602,12 @@ def list_slices(
:return: table in format specified by output parameter
:param pretty_names: pretty_names
:type pretty_names: bool
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool
:rtype: Object
"""
table = []
for slice in self.get_slices(excludes=excludes):
for slice in self.get_slices(excludes=excludes, user_only=user_only):
table.append(slice.toDict())

if pretty_names:
Expand All @@ -1610,6 +1633,7 @@ def show_slice(
fields=None,
quiet=False,
pretty_names=True,
user_only: bool = True,
):
"""
Show a table with all the properties of a specific site
Expand Down Expand Up @@ -1637,11 +1661,13 @@ def show_slice(
:type quiet: bool
:param pretty_names: pretty_names
:type pretty_names: bool
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool
:return: table in format specified by output parameter
:rtype: Object
"""

slice = self.get_slice(name=name, slice_id=id)
slice = self.get_slice(name=name, slice_id=id, user_only=user_only)

return slice.show(
output=output, fields=fields, quiet=quiet, pretty_names=pretty_names
Expand All @@ -1652,6 +1678,7 @@ def get_slices(
excludes: List[SliceState] = [SliceState.Dead, SliceState.Closing],
slice_name: str = None,
slice_id: str = None,
user_only: bool = True,
) -> List[Slice]:
"""
Gets a list of slices from the slice manager.
Expand All @@ -1664,6 +1691,8 @@ def get_slices(
:type excludes: List[SliceState]
:param slice_name:
:param slice_id:
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool

:return: a list of slices
:rtype: List[Slice]
Expand All @@ -1674,7 +1703,11 @@ def get_slices(
start = time.time()

return_status, slices = self.get_slice_manager().slices(
excludes=excludes, name=slice_name, slice_id=slice_id, limit=200
excludes=excludes,
name=slice_name,
slice_id=slice_id,
limit=200,
user_only=user_only,
)

if self.get_log_level() == logging.DEBUG:
Expand All @@ -1686,12 +1719,16 @@ def get_slices(
return_slices = []
if return_status == Status.OK:
for slice in slices:
return_slices.append(Slice.get_slice(self, sm_slice=slice))
return_slices.append(
Slice.get_slice(self, sm_slice=slice, user_only=user_only)
)
else:
raise Exception(f"Failed to get slices: {slices}")
return return_slices

def get_slice(self, name: str = None, slice_id: str = None) -> Slice:
def get_slice(
self, name: str = None, slice_id: str = None, user_only: bool = True
) -> Slice:
"""
Gets a slice by name or slice_id. Dead and Closing slices may have
non-unique names and must be queried by slice_id. Slices in all other
Expand All @@ -1704,14 +1741,18 @@ def get_slice(self, name: str = None, slice_id: str = None) -> Slice:
:type name: String
:param slice_id: The ID of the desired slice
:type slice_id: String
:param user_only: True indicates return own slices; False indicates return project slices
:type user_only: bool
:raises: Exception: if slice name or slice id are not inputted
:return: the slice, if found
:rtype: Slice
"""
# Get the appropriate slices list
if slice_id:
# if getting by slice_id consider all slices
slices = self.get_slices(excludes=[], slice_id=slice_id)
slices = self.get_slices(
excludes=[], slice_id=slice_id, user_only=user_only
)

if len(slices) == 1:
return slices[0]
Expand All @@ -1720,7 +1761,9 @@ def get_slice(self, name: str = None, slice_id: str = None) -> Slice:
elif name:
# if getting by name then only consider active slices
slices = self.get_slices(
excludes=[SliceState.Dead, SliceState.Closing], slice_name=name
excludes=[SliceState.Dead, SliceState.Closing],
slice_name=name,
user_only=user_only,
)

if len(slices) > 0:
Expand Down
6 changes: 3 additions & 3 deletions fabrictestbed_extensions/fablib/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ def toDict(self, skip=[]):
"network": str(network_name),
"bandwidth": str(self.get_bandwidth()),
"mode": str(self.get_mode()),
"vlan": str(self.get_vlan())
if self.get_vlan()
else "", # str(self.get_vlan()),
"vlan": (
str(self.get_vlan()) if self.get_vlan() else ""
), # str(self.get_vlan()),
"mac": mac,
"physical_dev": physical_dev,
"dev": dev,
Expand Down
13 changes: 7 additions & 6 deletions fabrictestbed_extensions/fablib/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,14 +311,14 @@ def generate_template_context(self):

return context

def get_template_context(self):
return self.get_slice().get_template_context(self, skip=["ssh_command"])
def get_template_context(self, skip: List[str] = ["ssh_command"]):
return self.get_slice().get_template_context(self, skip=skip)

def render_template(self, input_string):
def render_template(self, input_string, skip: List[str] = ["ssh_command"]):
environment = jinja2.Environment()
# environment.json_encoder = json.JSONEncoder(ensure_ascii=False)
template = environment.from_string(input_string)
output_string = template.render(self.get_template_context())
output_string = template.render(self.get_template_context(skip=skip))

return output_string

Expand Down Expand Up @@ -1169,7 +1169,8 @@ def get_ssh_command(self) -> str:

try:
return self.render_template(
self.get_fablib_manager().get_ssh_command_line()
self.get_fablib_manager().get_ssh_command_line(),
skip=["ssh_command", "interfaces"],
)
except:
return self.get_fablib_manager().get_ssh_command_line()
Expand Down Expand Up @@ -1557,7 +1558,7 @@ def execute(

except Exception as e:
logging.warning(
f"Exception in node.execute() (attempt #{attempt} of {retry}): {e}"
f"Exception in node.execute() command: {command} (attempt #{attempt} of {retry}): {e}"
)

if attempt + 1 == retry:
Expand Down
46 changes: 28 additions & 18 deletions fabrictestbed_extensions/fablib/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -1117,15 +1117,21 @@ def __str__(self) -> str:
fp.site,
iface.node_id,
iface.labels.vlan_range if iface.labels else "N/A",
iface.labels.local_name
if iface.labels and iface.labels.local_name
else "N/A",
iface.labels.device_name
if iface.labels and iface.labels.device_name
else "N/A",
iface.labels.region
if iface.labels and iface.labels.region
else "N/A",
(
iface.labels.local_name
if iface.labels and iface.labels.local_name
else "N/A"
),
(
iface.labels.device_name
if iface.labels and iface.labels.device_name
else "N/A"
),
(
iface.labels.region
if iface.labels and iface.labels.region
else "N/A"
),
]
)

Expand Down Expand Up @@ -1156,15 +1162,19 @@ def fp_to_dict(self, iface: interface.Interface, name: str, site: str) -> dict:
"site_name": site,
"node_id": iface.node_id,
"vlan_range": iface.labels.vlan_range if iface.labels else "N/A",
"local_name": iface.labels.local_name
if iface.labels and iface.labels.local_name
else "N/A",
"device_name": iface.labels.device_name
if iface.labels and iface.labels.device_name
else "N/A",
"region": iface.labels.region
if iface.labels and iface.labels.region
else "N/A",
"local_name": (
iface.labels.local_name
if iface.labels and iface.labels.local_name
else "N/A"
),
"device_name": (
iface.labels.device_name
if iface.labels and iface.labels.device_name
else "N/A"
),
"region": (
iface.labels.region if iface.labels and iface.labels.region else "N/A"
),
}

def list_facility_ports(
Expand Down
Loading
Loading