iLO-manager first main commitgit status
This commit is contained in:
1 parent
e6f4cc04ca
commit
599d8da562
3271 files changed
+550655
No files matched your search
@@ -0,0 +1,228 @@
|
||||
"""
|
||||
conftest.py is used to set up shared fixtures, plugins, hooks, other config etc.
|
||||
This is the functional test conftest.py
|
||||
http://docs.pytest.org/en/latest/writing_plugins.html#conftest-py-local-per-directory-plugins
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
|
||||
import pytest
|
||||
|
||||
import redfish
|
||||
|
||||
# For cross-compatibility between Python 2 and Python 3
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
except ImportError:
|
||||
from urlparse import urlparse
|
||||
|
||||
from ..conftest import RDMC_FILE
|
||||
from . import utils
|
||||
from .ilomock import MockServer
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def mock_server():
|
||||
with MockServer() as server:
|
||||
yield server
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dl360_large(mock_server):
|
||||
"""Returns a mock server config:
|
||||
|
||||
- DL360 Gen10
|
||||
- 1x AEP DIMM
|
||||
- 1x DRAM DIMM
|
||||
"""
|
||||
data_dir = os.path.join(os.path.dirname(__file__), 'mockdata/dl360-large')
|
||||
mock_server.load(data_dir)
|
||||
return MockServerConfig(mock_server, username='rev', password='hpe123')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dl360_memfast_disabled(dl360_large):
|
||||
"""Returns a dl360_configured config with MemFastTraining disabled
|
||||
"""
|
||||
dl360_large.patch('/redfish/v1/systems/1/bios/settings/', {'Attributes': {'MemFastTraining': 'Disabled'}})
|
||||
|
||||
return dl360_large
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def test_server():
|
||||
"""Returns a server config specified by the TEST_SERVER environment variable.
|
||||
|
||||
TEST_SERVER should be a URL with optional auth, e.g. https://user:password@host:port
|
||||
"""
|
||||
if 'TEST_SERVER' not in os.environ:
|
||||
pytest.skip("TEST_SERVER not set")
|
||||
|
||||
url, username, password = utils.urlparse_auth(os.getenv('TEST_SERVER'))
|
||||
# If no credentials, then populate with hard-coded values. Credentials required by ilorest.
|
||||
username = "orange" if username is None else username
|
||||
password = "password" if password is None else password
|
||||
return ServerConfig(url=url, username=username, password=password)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ilorest(tmpdir):
|
||||
"""Returns an ilorest session (in scripting mode by default).
|
||||
|
||||
Each ilorest session receives its own unique temporary cache directory.
|
||||
"""
|
||||
yield Ilorest(cache_dir=tmpdir.dirname)
|
||||
tmpdir.remove(ignore_errors=True)
|
||||
|
||||
|
||||
class ServerConfig(object):
|
||||
|
||||
def __init__(self, url=None, username=None, password=None):
|
||||
self.url = url
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
return self.url, self.username, self.password
|
||||
|
||||
@property
|
||||
def hostname(self):
|
||||
parts = urlparse(self.url)
|
||||
hostname = parts.hostname if parts.scheme else self.url
|
||||
return hostname
|
||||
|
||||
|
||||
class MockServerConfig(ServerConfig):
|
||||
|
||||
def __init__(self, server, username=None, password=None):
|
||||
super(MockServerConfig, self).__init__(url=server.url, username=username, password=password)
|
||||
self.server = server
|
||||
|
||||
def patch(self, path, data):
|
||||
"""Patches a resource in the mock server."""
|
||||
self.server.patch(path, data)
|
||||
|
||||
|
||||
class Ilorest(object):
|
||||
"""Wrapper for the iLO RESTful Interface Tool."""
|
||||
|
||||
def __init__(self, cache_dir=None):
|
||||
"""Starts ilorest in scripting mode.
|
||||
|
||||
:param cache_dir: directory to use for caching instead of the default global location
|
||||
"""
|
||||
self.cache_dir = cache_dir
|
||||
self.args = [sys.executable, RDMC_FILE]
|
||||
|
||||
if cache_dir:
|
||||
self.args.append('--cache-dir={}'.format(cache_dir))
|
||||
|
||||
self.interactive = False
|
||||
self.proc = None
|
||||
self.prompt = "iLOrest > "
|
||||
|
||||
def run(self, args, sendline=None):
|
||||
"""Runs an ilorest command.
|
||||
|
||||
:param args: list of command arguments
|
||||
:param sendline: string to send after running (only used in interactive mode)
|
||||
:return: results of the command as a named tuple: (stdout, stderr, retcode)
|
||||
"""
|
||||
if not self.interactive:
|
||||
return utils.run_cmd(self.args + args)
|
||||
|
||||
# interactive mode
|
||||
cmd_line = ' '.join(args)
|
||||
self.proc.sendline(cmd_line)
|
||||
if sendline:
|
||||
self.proc.sendline(sendline)
|
||||
|
||||
stdout, stderr = self.proc.read(expect=self.prompt)
|
||||
|
||||
match = re.search("iLOrest return code: ([0-9]+)\n", stdout)
|
||||
retcode = int(match.group(1)) if match else None
|
||||
|
||||
return utils.CommandResult(stdout=stdout, stderr=stderr, retcode=retcode)
|
||||
|
||||
def login(self, url=None, username=None, password=None):
|
||||
"""Logs in to the server and establishes a secure session.
|
||||
|
||||
:param url: iLO server url if connecting remotely
|
||||
:param username: iLO username. If no username specified, use "orange"
|
||||
:param password: iLO password. If no password specified, use "password"
|
||||
"""
|
||||
args = ['login']
|
||||
if url:
|
||||
args.append(url)
|
||||
if username:
|
||||
args.extend(['-u', username])
|
||||
if password:
|
||||
args.extend(['-p', password])
|
||||
|
||||
results = self.run(args)
|
||||
assert results.retcode == 0, "Failed to connect or log in"
|
||||
|
||||
def logout(self):
|
||||
"""Ends the current session and disconnects from the server."""
|
||||
self.run(['logout'])
|
||||
|
||||
@contextmanager
|
||||
def session(self, url=None, username=None, password=None):
|
||||
"""Establishes a session with an iLO server and logs out afterwards."""
|
||||
self.login(url=url, username=username, password=password)
|
||||
yield self
|
||||
self.logout()
|
||||
|
||||
@contextmanager
|
||||
def interactive_session(self, url=None, username=None, password=None):
|
||||
"""Establishes an interactive session with an iLO server, and logs out and exits afterwards."""
|
||||
with self.interactive_mode(), self.session(url=url, username=username, password=password):
|
||||
yield self
|
||||
|
||||
@contextmanager
|
||||
def interactive_mode(self):
|
||||
"""Enters interactive mode and exits afterwards."""
|
||||
# use --verbose to extract the return code
|
||||
self.proc = utils.InteractivePopen(self.args + ['--verbose'])
|
||||
self.proc.read(expect=self.prompt)
|
||||
self.interactive = True
|
||||
yield self
|
||||
self.proc.communicate('exit')
|
||||
self.interactive = False
|
||||
|
||||
|
||||
class RestClient(object):
|
||||
"""REST client for an iLO server."""
|
||||
|
||||
def __init__(self, url=None, username=None, password=None):
|
||||
"""Initializes an iLO REST client.
|
||||
|
||||
:param url: iLO server url if connecting remotely
|
||||
:param username: iLO username
|
||||
:param password: iLO password
|
||||
"""
|
||||
# if no scheme/protocol defined, try https
|
||||
if "://" not in url:
|
||||
url = "https://" + url
|
||||
self._client = redfish.redfish_client(base_url=url, username=username, password=password)
|
||||
self._client.login(auth=redfish.AuthMethod.BASIC)
|
||||
|
||||
def get(self, path):
|
||||
"""Sends a GET request."""
|
||||
resp = self._client.get(path)
|
||||
return resp.dict
|
||||
|
||||
def patch(self, path, body):
|
||||
"""
|
||||
Sends a PATCH request to the path with the given body
|
||||
:param path: URI path
|
||||
:param body: the body of the patch. For example dict:{ "Attributes": { "Prop1": true } }
|
||||
:return: RestResponse status, RestResponse dictionary
|
||||
"""
|
||||
rest_response = self._client.patch(path=path, body=body)
|
||||
return rest_response.status, rest_response.dict
|
||||
Reference in new issue
Block a user