Skip to content

Commit f530ae3

Browse files
committed
connect and disconnect with high level commands - ixDis/connectFromChassis
1 parent 477f693 commit f530ae3

10 files changed

Lines changed: 115 additions & 48 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This workflow will upload a Python Package using Twine when a release is created
2+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3+
4+
name: Upload Python Package
5+
6+
on:
7+
release:
8+
types: [created]
9+
10+
jobs:
11+
deploy:
12+
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- name: Set up Python
18+
uses: actions/setup-python@v2
19+
with:
20+
python-version: '3.x'
21+
- name: Build and publish
22+
env:
23+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
24+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
25+
run: |
26+
make install
27+
make build
28+
twine upload dist/*

.github/workflows/python-push.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# This workflow will only install Python dependencies to verify correct installation.
2+
# TODO: Fix all pre-commit issues and run pre-commit.
3+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
4+
5+
name: Python package
6+
7+
on:
8+
push:
9+
branches: [ master, dev ]
10+
pull_request:
11+
branches: [ master, dev ]
12+
13+
jobs:
14+
build:
15+
16+
runs-on: ubuntu-latest
17+
strategy:
18+
matrix:
19+
python-version: ["3.7", "3.8", "3.9", "3.10"]
20+
21+
steps:
22+
- uses: actions/checkout@v2
23+
- name: Set up Python ${{ matrix.python-version }}
24+
uses: actions/setup-python@v2
25+
with:
26+
python-version: ${{ matrix.python-version }}
27+
- name: Install dependencies
28+
run: |
29+
make install

ixexplorer/api/tclproto.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ class TclError(Exception):
3030
def __init__(self, result):
3131
self.result = result
3232

33-
def __str__(self):
34-
return "%s: %s" % (self.__class__.__name__, self.result)
33+
def __str__(self) -> str:
34+
return f"{self.__class__.__name__}: {self.result}"
3535

3636

3737
class TclClient:
@@ -112,7 +112,7 @@ def call(self, string, *args):
112112
else:
113113
return self.ssh_call(string, *args)
114114

115-
def connect(self):
115+
def connect(self) -> None:
116116
self.logger.debug(f"Opening connection to {self.host}:{self.port}")
117117

118118
if self.port == 8022:
@@ -133,7 +133,7 @@ def connect(self):
133133
self.call("package req IxTclHal")
134134
self.call("enableEvents true")
135135

136-
def close(self):
136+
def close(self) -> None:
137137
self.logger.debug("Closing connection")
138138
self.fd.close()
139139
self.fd = None

ixexplorer/ixe_app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def add(self, chassis: str) -> None:
5858
:param chassis: chassis IP address.
5959
"""
6060
if chassis not in self.chassis_chain:
61-
self.chassis_chain[chassis] = IxeChassis(self.session, chassis, len(self.chassis_chain) + 1)
61+
self.chassis_chain[chassis] = IxeChassis(self.session, chassis)
6262
self.chassis_chain[chassis].connect()
6363

6464
def discover(self) -> None:

ixexplorer/ixe_hw.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
1+
"""
2+
Classes to manage IxExplorer HW objects - chassis, card and resource group.
3+
Port class in in ixe_port module.
4+
"""
15
import re
26
from collections import OrderedDict
3-
from typing import Dict
7+
from typing import TYPE_CHECKING, Dict
48

59
from trafficgenerator.tgn_tcl import tcl_list_2_py_list
610

711
from ixexplorer.api.ixapi import FLAG_RDONLY, IxTclHalError, TclMember, ixe_obj_meta
812
from ixexplorer.ixe_object import IxeObject, IxeObjectObj
913
from ixexplorer.ixe_port import IxePort
1014

15+
if TYPE_CHECKING:
16+
from ixexplorer.ixe_app import IxeSession
17+
1118

1219
class IxeCard(IxeObject, metaclass=ixe_obj_meta):
1320
__tcl_command__ = "card"
@@ -33,7 +40,7 @@ class IxeCard(IxeObject, metaclass=ixe_obj_meta):
3340
def __init__(self, parent, uri):
3441
super().__init__(parent=parent, uri=uri.replace("/", " "))
3542

36-
def discover(self):
43+
def discover(self) -> None:
3744
self.logger.info("Discover card {}".format(self.obj_name()))
3845
for pid in range(1, self.portCount + 1):
3946
IxePort(self, self.uri + "/" + str(pid))
@@ -60,7 +67,7 @@ def discover(self):
6067
ports = range(1, 13)
6168
operationMode = "1000"
6269
IxeResourceGroup(self, 1, operationMode, -1, ports, ports, ports)
63-
except Exception as _:
70+
except Exception:
6471
print("no resource group support")
6572

6673
def add_vm_port(self, port_id, nic_id, mac, promiscuous=0, mtu=1500, speed=1000):
@@ -84,18 +91,15 @@ def get_resource_group(self):
8491

8592
resourceGroup = property(get_resource_group)
8693

87-
def write(self):
94+
def write(self) -> None:
8895
self.ix_command("write")
8996

9097
#
9198
# Properties.
9299
#
93100

94-
def get_ports(self):
95-
"""
96-
:return: dictionary {index: object} of all ports.
97-
"""
98-
101+
def get_ports(self) -> Dict[int, IxePort]:
102+
"""Get dictionary {index: object} of all ports."""
99103
return {int(p.index): p for p in self.get_objects_by_type("port")}
100104

101105
ports = property(get_ports)
@@ -205,27 +209,35 @@ class IxeChassis(IxeObject, metaclass=ixe_obj_meta):
205209
OS_WIN2000 = 3
206210
OS_WINXP = 4
207211

208-
def __init__(self, parent, host, chassis_id=1):
212+
def __init__(self, parent: "IxeSession", host: str) -> None:
213+
"""Create IxeChassis object with name = url == IP address."""
209214
super().__init__(parent=parent, uri=host, name=host)
210-
self.chassis_id = chassis_id
215+
self.chassis_id = 0
211216

212217
def connect(self) -> None:
213-
self.add()
214-
self.id = self.chassis_id
218+
"""Connect to chassis and get assigned chassis ID.
219+
220+
Note that sometimes, randomly, ixConnectToChassis fails. However, using chassis.add also fails, so it seems there is
221+
no advantage for using one over the other.
222+
"""
223+
self.api.call_rc(f"ixConnectToChassis {self.uri}")
224+
self.chassis_id = self.id
215225

216226
def disconnect(self) -> None:
217-
self.ix_command("del")
227+
"""Disconnect from chassis."""
228+
self.api.call_rc(f"ixDisconnectFromChassis {self.uri}")
218229

219230
def add_card(self, cid):
220-
"""
231+
"""Add card.
232+
221233
There is no config option which cards are used. So we have to iterate over all possible card ids and check if we are
222234
able to get a handle.
223235
"""
224236
card = IxeCard(self, str(self.chassis_id) + "/" + str(cid))
225237
try:
226238
card.discover()
227239
except IxTclHalError:
228-
self.logger.info(f"slot {cid} is empty")
240+
self.logger.info(f"Slot {cid} is empty")
229241
card.del_object_from_parent()
230242

231243
def discover(self) -> None:

ixexplorer/ixe_object.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,14 @@ def __init__(self, parent, **data):
2222
self._data["index"] = int(self.uri.split()[-1])
2323
self.__class__.current_object = None
2424

25-
def obj_uri(self):
26-
"""
27-
:return: object URI.
28-
"""
25+
def obj_uri(self) -> str:
26+
"""Object URI."""
2927
return str(self._data["uri"])
3028

3129
uri = property(obj_uri)
3230

3331
def get_objects_by_type(self, *types: str) -> List[TgnObject]:
34-
"""Overrides IxeObject.get_objects_by_type because `type` is an attribute name in some IxExpolorer objects."""
32+
"""Override IxeObject.get_objects_by_type because `type` is an attribute name in some IxExplorer objects."""
3533
if not types:
3634
return list(self.objects.values())
3735
types_l = [o.lower() for o in types]
@@ -40,16 +38,16 @@ def get_objects_by_type(self, *types: str) -> List[TgnObject]:
4038
def ix_command(self, command, *args, **kwargs):
4139
return self.api.call(("{} {} {}" + len(args) * " {}").format(self.__tcl_command__, command, self.uri, *args))
4240

43-
def ix_set_default(self):
41+
def ix_set_default(self) -> None:
4442
self.api.call("{} setDefault".format(self.__tcl_command__))
4543
self.__class__.current_object = self
4644

47-
def ix_get(self, member=None, force=False):
45+
def ix_get(self, member=None, force=False) -> None:
4846
if (self != self.__class__.current_object or force) and self.__get_command__:
4947
self.api.call_rc("{} {} {}".format(self.__tcl_command__, self.__get_command__, self.uri))
5048
self.__class__.current_object = self
5149

52-
def ix_set(self, member=None):
50+
def ix_set(self, member=None) -> None:
5351
self.api.call_rc("{} {} {}".format(self.__tcl_command__, self.__set_command__, self.uri))
5452

5553
def get_attributes(self, flags=0xFF, *attributes):
@@ -65,7 +63,7 @@ def get_attribute(self, attribute):
6563
"""Abstract method - must implement - do not call directly."""
6664
return getattr(self, attribute)
6765

68-
def set_attributes(self, **attributes):
66+
def set_attributes(self, **attributes) -> None:
6967
"""Set group of attributes without calling set between attributes regardless of global auto_set.
7068
7169
Set will be called only after all attributes are set based on global auto_set.
@@ -85,11 +83,11 @@ def get_auto_set(cls):
8583
return ixe_obj_auto_set
8684

8785
@classmethod
88-
def set_auto_set(cls, auto_set):
86+
def set_auto_set(cls, auto_set) -> None:
8987
global ixe_obj_auto_set
9088
ixe_obj_auto_set = auto_set
9189

92-
def _reset_current_object(self):
90+
def _reset_current_object(self) -> None:
9391
self.__class__.current_object = None
9492
for child in self.objects.values():
9593
child._reset_current_object()

ixexplorer/ixe_pg.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,41 +40,41 @@ def del_port(self, port):
4040
def _set_command(self, cmd):
4141
self.api.call_rc("portGroup setCommand {} {}".format(self.uri, cmd))
4242

43-
def start_transmit(self, blocking=False):
43+
def start_transmit(self, blocking=False) -> None:
4444
"""
4545
:param blocking: True - wait for transmit end, False - return immediately.
4646
:todo: implement blocking.
4747
"""
4848
self.set_command(self.START_TRANSMIT)
4949

50-
def stop_transmit(self):
50+
def stop_transmit(self) -> None:
5151
self.set_command(self.STOP_TRANSMIT)
5252

53-
def start_capture(self):
53+
def start_capture(self) -> None:
5454
self.set_command(self.START_CAPTURE)
5555

56-
def stop_capture(self):
56+
def stop_capture(self) -> None:
5757
self.set_command(self.STOP_CAPTURE)
5858

59-
def reset_statistics(self):
59+
def reset_statistics(self) -> None:
6060
self.set_command(self.RESET_STATISTICS)
6161

62-
def pause_transmit(self):
62+
def pause_transmit(self) -> None:
6363
self.set_command(self.PAUSE_TRANSMIT)
6464

65-
def step_transmit(self):
65+
def step_transmit(self) -> None:
6666
self.set_command(self.STEP_TRANSMIT)
6767

68-
def transmit_ping(self):
68+
def transmit_ping(self) -> None:
6969
self.set_command(self.TRANSMIT_PING)
7070

71-
def take_ownership(self, force=False):
71+
def take_ownership(self, force: bool = False) -> None:
7272
if not force:
7373
self.set_command(self.TAKE_OWNERSHIP)
7474
else:
7575
self.set_command(self.TAKE_OWNERSHIP_FORCED)
7676

77-
def clear_ownership(self, force=False):
77+
def clear_ownership(self, force: bool = False) -> None:
7878
if not force:
7979
self.set_command(self.CLEAR_OWNERSHIP)
8080
else:

ixexplorer/ixe_stream.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def __init__(self, parent, uri):
7474
super().__init__(parent=parent, uri=uri.replace("/", " "))
7575
self.rx_ports = []
7676

77-
def create(self, name):
77+
def create(self, name: str) -> None:
7878
self.ix_set_default()
7979
self.protocol.ix_set_default()
8080
self.vlan.ix_set_default()
@@ -85,13 +85,13 @@ def create(self, name):
8585
self.packetGroup.groupId = IxeStream.next_group_id
8686
IxeStream.next_group_id += 1
8787

88-
def remove(self):
88+
def remove(self) -> None:
8989
self.ix_command("remove")
9090
self.ix_command("write")
9191
self.del_object_from_parent()
9292

93-
def ix_set_default(self):
94-
super(self.__class__, self).ix_set_default()
93+
def ix_set_default(self) -> None:
94+
super().ix_set_default()
9595
for stream_object in [o for o in self.__dict__.values() if isinstance(o, IxeStreamObj)]:
9696
stream_object.ix_set_default()
9797

ixexplorer/samples/tcl_cli.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/env python
22
# encoding: utf-8
3-
43
import logging
54
import sys
65
from optparse import OptionParser
@@ -10,7 +9,7 @@
109
rsa_id = "C:/Program Files (x86)/Ixia/IxOS/9.10.2000.31/TclScripts/lib/ixTcl1.0/id_rsa"
1110

1211

13-
def main():
12+
def main() -> None:
1413
usage = "usage: %prog [options] <host>"
1514
parser = OptionParser(usage=usage)
1615
parser.add_option("-a", action="store_true", dest="autoconnect", help="autoconnect to chassis")

tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# pylint: disable=redefined-outer-name
12
from typing import Iterable, List
23

34
import pytest

0 commit comments

Comments
 (0)