diff --git a/cterasdk/edge/__init__.py b/cterasdk/edge/__init__.py index be39ec2b..512b5da3 100644 --- a/cterasdk/edge/__init__.py +++ b/cterasdk/edge/__init__.py @@ -30,6 +30,7 @@ 'shares', 'shell', 'smb', + 'statistics', 'support', 'sync', 'syslog', diff --git a/cterasdk/edge/enum.py b/cterasdk/edge/enum.py index 611f652a..7e2b66db 100644 --- a/cterasdk/edge/enum.py +++ b/cterasdk/edge/enum.py @@ -437,3 +437,43 @@ class ResourceError: """ FileExists = 'File exists' Forbidden = 'Creating a folder in this location is forbidden' + + +class Metric: + """ + Metric + + :ivar str CPU: CPU + :ivar str Memory: Memory + :ivar str Volume: Volume + :ivar str Cache: Cache Stats + :ivar str Connections: Connections + :ivar str Disk: Disk I/O + :ivar str Local: Local I/O + :ivar str CloudSync: Cloud Sync + """ + CPU = 'cpu' + Memory = 'memory' + Volume = 'volume' + Cache = 'cache' + Connections = 'connections' + Disk = 'disk_io' + Local = 'local_io' + CloudSync = 'cloud_io' + + +class Interval: + """ + Interval + + :ivar str Hour: Hour (Real-time) + :ivar str Day: Day + :ivar str Week: Week + :ivar str Month: Month + :ivar str Year: Year + """ + Hour = 'hour' + Day = 'day' + Week = 'week' + Month = 'month' + Year = 'year' diff --git a/cterasdk/edge/remote.py b/cterasdk/edge/remote.py index 67b4645f..e5d71c86 100644 --- a/cterasdk/edge/remote.py +++ b/cterasdk/edge/remote.py @@ -14,7 +14,7 @@ def remote_access(device, Portal): logger.info("Enabling remote access. %s", {'tenant': device_tenant, 'device': device_name}) token = authn_token(Portal, device_tenant, device_name) device_object = create_device_object(device) - device_object.sso(token) + device_object.sso(token, {Portal._session_id_key: Portal.get_session_id()}) # pylint: disable=protected-access logger.info("Enabled remote access. %s", {'tenant': device_tenant, 'device': device_name}) return device_object diff --git a/cterasdk/edge/statistics.py b/cterasdk/edge/statistics.py new file mode 100644 index 00000000..9f70a6a9 --- /dev/null +++ b/cterasdk/edge/statistics.py @@ -0,0 +1,91 @@ +from .enum import Metric +from .base_command import BaseCommand + + +class Statistics(BaseCommand): + """ Edge Filer Statistics API """ + + def cpu(self, interval): + """ + CPU Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.CPU, interval) + + def memory(self, interval): + """ + Memory Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.Memory, interval) + + def volume(self, interval): + """ + Volume Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.Volume, interval) + + def cache(self, interval): + """ + Cache Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.Cache, interval) + + def connections(self, interval): + """ + Connections Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.Connections, interval) + + def disk(self, interval): + """ + Disk I/O Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.Disk, interval) + + def local_io(self, interval): + """ + Local I/O Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.Local, interval) + + def cloudsync(self, interval): + """ + Cloud Synchronization Statistics + + :param cterasdk.edge.enum.Interval interval: Interval + :return: Statistics Object + :rtype: cterasdk.common.object.Object + """ + return self._statistics(Metric.CloudSync, interval) + + def _statistics(self, metric, interval): + return self._edge.clients.stats.get(metric, params={ + 'interval': interval + }) diff --git a/cterasdk/objects/services.py b/cterasdk/objects/services.py index fe5e1571..75c5a700 100644 --- a/cterasdk/objects/services.py +++ b/cterasdk/objects/services.py @@ -143,13 +143,13 @@ def test(self): def _session_id_key(self): return NotImplementedError("Subclass must implement the '_session_id_key' property") - def get_session_id(self): + def get_session_id(self, response_url=None): """ Get Session Identifier :return str: Session ID """ - return self._default.cookie_jar.get(self._default.baseurl, self._session_id_key) + return self._default.cookie_jar.get(response_url if response_url else self._default.baseurl, self._session_id_key) def set_session_id(self, session_id): self._default.cookie_jar.update_cookies({self._session_id_key: session_id}, self._default.baseurl) diff --git a/cterasdk/objects/synchronous/core.py b/cterasdk/objects/synchronous/core.py index 0b1769de..eb77bee3 100644 --- a/cterasdk/objects/synchronous/core.py +++ b/cterasdk/objects/synchronous/core.py @@ -93,6 +93,9 @@ def context(self): def _session_id_key(self): return 'JSESSIONID' + def get_session_id(self): # pylint: disable=arguments-differ + return super().get_session_id(self.ctera.baseurl) + def _authenticator(self, url): return authenticators.core(self.session(), url, self.context) diff --git a/cterasdk/objects/synchronous/edge.py b/cterasdk/objects/synchronous/edge.py index dbe2c9ba..46642f98 100644 --- a/cterasdk/objects/synchronous/edge.py +++ b/cterasdk/objects/synchronous/edge.py @@ -11,7 +11,7 @@ afp, aio, antivirus, array, audit, backup, cache, cli, config, connection, ctera_migrate, dedup, directoryservice, drive, files, firmware, ftp, groups, licenses, login, logs, mail, network, nfs, ntp, power, remote, rsync, ransom_protect, services, - shares, shell, smb, snmp, ssh, ssl, support, sync, syslog, tasks, telnet, + shares, shell, smb, snmp, ssh, ssl, statistics, support, sync, syslog, tasks, telnet, timezone, users, volumes, ) @@ -27,6 +27,7 @@ def __init__(self, edge, Portal): else: self.migrate = edge.default.clone(clients.Migrate, EndpointBuilder.new(edge.base, '/migration/rest/v1')) self.api = edge.default.clone(clients.API, EndpointBuilder.new(edge.base, '/admingui/api')) + self.stats = edge.default.clone(clients.JSON, EndpointBuilder.new(edge.base, '/stats')) self.io = IO(edge) @@ -108,6 +109,7 @@ def __init__(self, host=None, port=None, https=True, Portal=None, *, base=None): self.snmp = snmp.SNMP(self) self.ssh = ssh.SSH(self) self.ssl = modules.initialize(ssl.SSLModule, self) + self.statistics = statistics.Statistics(self) self.support = support.Support(self) self.sync = sync.Sync(self) self.syslog = syslog.Syslog(self) @@ -151,8 +153,14 @@ def initialized(self): def test(self): return connection.test(self) - def sso(self, ticket): - """ Login using Single Sign On""" + def sso(self, ticket, session): + """ + Single Sign on from CTERA Portal to CTERA Edge Filer. + + :param str ticket: SSO Ticket + :param dict session: CTERA Portal Session Cookie + """ + self.default.cookie_jar.update_cookies(session, self.default.baseurl) self._login_object.sso(ticket) self.session().start_session(self) @@ -164,5 +172,5 @@ def _omit_fields(self): return super()._omit_fields + ['afp', 'aio', 'array', 'audit', 'antivirus', 'backup', 'cache', 'cli', 'config', 'ctera_migrate', 'dedup', 'directoryservice', 'drive', 'files', 'firmware', 'ftp', 'groups', 'licenses', 'logs', 'mail', 'network', 'nfs', 'ntp', 'power', 'ransom_protect', 'rsync', 'services', 'shares', 'shell', - 'smb', 'snmp', 'ssh', 'ssl', 'support', 'sync', 'syslog', 'tasks', 'telnet', 'timezone', - 'users', 'volumes'] + 'smb', 'snmp', 'ssh', 'ssl', 'statistics', 'support', 'sync', 'syslog', 'tasks', 'telnet', + 'timezone', 'users', 'volumes'] diff --git a/docs/source/UserGuides/Edge/Configuration.rst b/docs/source/UserGuides/Edge/Configuration.rst index 95ef3092..96eb5333 100644 --- a/docs/source/UserGuides/Edge/Configuration.rst +++ b/docs/source/UserGuides/Edge/Configuration.rst @@ -1505,6 +1505,65 @@ SSH edge.ssh.disable() +Statistics +========== + +.. automethod:: cterasdk.edge.statistics.Statistics.cpu + :noindex: + +.. code-block:: python + + edge.statistics.cpu(edge_enum.Interval.Day) + +.. automethod:: cterasdk.edge.statistics.Statistics.memory + :noindex: + +.. code-block:: python + + edge.statistics.memory(edge_enum.Interval.Day) + +.. automethod:: cterasdk.edge.statistics.Statistics.volume + :noindex: + +.. code-block:: python + + edge.statistics.volume(edge_enum.Interval.Day) + +.. automethod:: cterasdk.edge.statistics.Statistics.cache + :noindex: + +.. code-block:: python + + edge.statistics.cache(edge_enum.Interval.Day) + +.. automethod:: cterasdk.edge.statistics.Statistics.connections + :noindex: + +.. code-block:: python + + edge.statistics.connections(edge_enum.Interval.Day) + +.. automethod:: cterasdk.edge.statistics.Statistics.disk + :noindex: + +.. code-block:: python + + edge.statistics.disk(edge_enum.Interval.Day) + +.. automethod:: cterasdk.edge.statistics.Statistics.local_io + :noindex: + +.. code-block:: python + + edge.statistics.local_io(edge_enum.Interval.Day) + +.. automethod:: cterasdk.edge.statistics.Statistics.cloudsync + :noindex: + +.. code-block:: python + + edge.statistics.cloudsync(edge_enum.Interval.Day) + Miscellaneous ------------- diff --git a/tests/ut/edge/test_statistics.py b/tests/ut/edge/test_statistics.py new file mode 100644 index 00000000..04e892e5 --- /dev/null +++ b/tests/ut/edge/test_statistics.py @@ -0,0 +1,62 @@ +from unittest import mock + +from cterasdk.edge import statistics +from cterasdk.edge.enum import Interval, Metric +from tests.ut.edge import base_edge + + +class TestEdgeStatistics(base_edge.BaseEdgeTest): + + def setUp(self): + super().setUp() + self._filer.clients.stats.get = mock.MagicMock() + self.intervals = (Interval.Hour, Interval.Day, Interval.Week, Interval.Month, Interval.Year) + + def test_cpu(self): + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).cpu(interval) + self._filer.clients.stats.get.assert_called_with(Metric.CPU, params={'interval': interval}) + + def test_memory(self): + self._init_filer() + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).memory(interval) + self._filer.clients.stats.get.assert_called_with(Metric.Memory, params={'interval': interval}) + + def test_volume(self): + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).volume(interval) + self._filer.clients.stats.get.assert_called_with(Metric.Volume, params={'interval': interval}) + + def test_cache(self): + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).cache(interval) + self._filer.clients.stats.get.assert_called_with(Metric.Cache, params={'interval': interval}) + + def test_connections(self): + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).connections(interval) + self._filer.clients.stats.get.assert_called_with(Metric.Connections, params={'interval': interval}) + + def test_disk(self): + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).disk(interval) + self._filer.clients.stats.get.assert_called_with(Metric.Disk, params={'interval': interval}) + + def test_local_io(self): + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).local_io(interval) + self._filer.clients.stats.get.assert_called_with(Metric.Local, params={'interval': interval}) + + def test_cloudsync(self): + for interval in self.intervals: + self._init_filer() + statistics.Statistics(self._filer).cloudsync(interval) + self._filer.clients.stats.get.assert_called_with(Metric.CloudSync, params={'interval': interval})