Skip to content
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
13 changes: 7 additions & 6 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,25 @@ jobs:
run:
runs-on: ubuntu-latest
env:
PYTHON: '3.9'
PYTHON: '3.12'
steps:
- uses: actions/checkout@master
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@master
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: '3.12'
cache: 'pip'
- name: Generate coverage report
run: |
pip install -r tests/test-requirements.txt
PYTHONPATH=src pytest --cov=./ --cov-report=xml --cov-config=.coveragerc -p no:warnings
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
env_vars: PYTHON
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false
fail_ci_if_error: true
verbose: true
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
* [Power State Control](#power-state-control)
* [Check Power State](#check-power-state)
* [Get Power Consumed](#get-power-consumed)
* [Resetting iDRAC](#resetting-idrac)
* [Resetting Dell iDRAC](#resetting-dell-idrac)
* [Resetting BMC](#resetting-bmc)
* [BIOS factory reset](#bios-factory-reset)
* [Check current boot order](#check-current-boot-order)
Expand Down Expand Up @@ -104,14 +104,14 @@ We're mostly concentrated on programmatically enforcing interface/device boot or
* Check current boot order
* Display current power consumption in watts
* Reboot host
* Reset iDRAC
* View, check and clear iDRAC jobs
* Reset Dell iDRAC
* View, check and clear Dell iDRAC jobs
* Revert to factory settings
* Check/set SRIOV
* Take a remote screenshot of server KVM console activity (Dell only).
* Support tokenized authentication
* Check and set BIOS attributes (e.g. setting UEFI or BIOS mode)
* Get firmware inventory of installed devices supported by iDRAC
* Get firmware inventory of installed devices supported by the BMC
* Check/ummount virtual media en-masse across a set of systems (SuperMicro only)
* Obtain limited hardware information (CPU, Memory, Interfaces)
* Bulk actions via plain text file with list of hosts for parallel execution
Expand All @@ -122,7 +122,7 @@ We're mostly concentrated on programmatically enforcing interface/device boot or
* (Dell) iDRAC7,8,9 or newer
* (Dell) Firmware version ```2.60.60.60``` or higher
* Any Redfish IPMI 2.0 support on non-Dell systems
* iDRAC administrative account
* BMC administrative account
* Python >= ```3.8``` or [podman](https://podman.io/getting-started/installation) as a container.
* python3-devel >= ```3.8``` (If using standalone or RPM package below).

Expand Down Expand Up @@ -326,7 +326,7 @@ badfish -H mgmt-your-server.example.com --boot-to-mac A9:BB:4B:50:CA:54
```

### Forcing a one time boot to a specific type
To force systems to perform a one-time boot to a specific type on the next subsequent reboot you can use the ```--boot-to-type``` option and pass as an argument the device type, as defined on the iDRAC interfaces yaml, that you want the one-time boot to be set to. For this action you must also include the path to your interfaces yaml. This will change the one time boot BIOS attributes OneTimeBootMode and OneTimeBootSeqDev and on the next reboot it will attempt to PXE boot or boot from the first interface defined for that host type on the interfaces yaml file.
To force systems to perform a one-time boot to a specific type on the next subsequent reboot you can use the ```--boot-to-type``` option and pass as an argument the device type, as defined on the interfaces yaml, that you want the one-time boot to be set to. For this action you must also include the path to your interfaces yaml. This will change the one time boot BIOS attributes OneTimeBootMode and OneTimeBootSeqDev and on the next reboot it will attempt to PXE boot or boot from the first interface defined for that host type on the interfaces yaml file.
```bash
badfish -H mgmt-your-server.example.com -i config/idrac_interfaces.yml --boot-to-type foreman
```
Expand Down Expand Up @@ -379,7 +379,7 @@ Partial Output:
- INFO - Current watts consumed: 213
```

### Resetting iDRAC
### Resetting Dell iDRAC
For the replacement of `racadm racreset`, the optional argument `--racreset` was added. When this argument is passed to ```badfish```, a graceful restart is triggered on the iDRAC itself.
```bash
badfish -H mgmt-your-server.example.com --racreset
Expand Down Expand Up @@ -408,7 +408,7 @@ badfish -H mgmt-your-server.example.com --factory-reset
```

### Check current boot order
To check the current boot order of a specific host you can use the ```--check-boot``` option which will return an ordered list of boot devices. Additionally you can pass the ```-i``` option which will in turn print on screen what type of host does the current boot order match as those defined on the iDRAC interfaces yaml.
To check the current boot order of a specific host you can use the ```--check-boot``` option which will return an ordered list of boot devices. Additionally you can pass the ```-i``` option which will in turn print on screen what type of host does the current boot order match as those defined on the interfaces yaml.
```bash
badfish -H mgmt-your-server.example.com -i config/idrac_interfaces.yml --check-boot
```
Expand All @@ -426,7 +426,7 @@ badfish -H mgmt-your-server.example.com -i config/idrac_interfaces.yml -t forem
```

### Firmware inventory
If you would like to get a detailed list of all the devices supported by iDRAC you can run ```badfish``` with the ```--firware-inventory``` option which will return a list of devices with additional device info.
If you would like to get a detailed list of all the devices supported by the BMC you can run ```badfish``` with the ```--firware-inventory``` option which will return a list of devices with additional device info.
```bash
badfish -H mgmt-your-server.example.com --firmware-inventory
```
Expand All @@ -438,7 +438,7 @@ badfish -H mgmt-your-server.example.com --firmware-inventory --delta mgmt-your-o
```

### Clear Job Queue
If you would like to clear all the jobs that are queued on the remote iDRAC you can run ```badfish``` with the ```--clear-jobs``` option which query for all active jobs in the iDRAC queue and will post a request to clear the queue.
If you would like to clear all the jobs that are queued on the remote BMC you can run ```badfish``` with the ```--clear-jobs``` option which query for all active jobs in the job queue and will post a request to clear the queue.
```bash
badfish -H mgmt-your-server.example.com --clear-jobs
```
Expand All @@ -450,7 +450,7 @@ badfish -H mgmt-your-server.example.com --clear-jobs --force
```

### List Job Queue
If you would like to list all active jobs that are queued on the remote iDRAC you can run ```badfish``` with the ```--ls-jobs``` option which query for all active jobs in the iDRAC queue and will return a list with all active items.
If you would like to list all active jobs that are queued on the remote BMC you can run ```badfish``` with the ```--ls-jobs``` option which query for all active jobs in the job queue and will return a list with all active items.
```bash
badfish -H mgmt-your-server.example.com --ls-jobs
```
Expand Down
5 changes: 3 additions & 2 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[tool.pytest.ini_options]
pythonpath = [".", "src"]
[pytest]
pythonpath = . src
asyncio_mode = auto
1 change: 1 addition & 0 deletions src/badfish/config.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
RETRIES = 30
TIMEOUT = 120
19 changes: 16 additions & 3 deletions src/badfish/helpers/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@

class HTTPClient:

def __init__(self, host: str, username: str, password: str, logger, retries: int = 15, insecure: bool = False):
def __init__(
self,
host: str,
username: str,
password: str,
logger,
retries: int = 15,
insecure: bool = False,
timeout: int = 120,
):
self.host = host
self.username = username
self.password = password
self.logger = logger
self.retries = retries
self.insecure = insecure
self.timeout = aiohttp.ClientTimeout(total=timeout)
self.host_uri = f"https://{host}"
self.redfish_uri = "/redfish/v1"
self.root_uri = f"{self.host_uri}{self.redfish_uri}"
Expand Down Expand Up @@ -93,15 +103,15 @@ async def get_raw(self, uri: str, _continue: bool = False, _get_token: bool = Fa
uri,
headers={"X-Auth-Token": self.token} if self.token else {},
ssl=False if self.insecure else True,
timeout=60,
timeout=self.timeout,
) as _response:
await _response.read()
else:
async with session.get(
uri,
auth=aiohttp.BasicAuth(self.username, self.password),
ssl=False if self.insecure else True,
timeout=60,
timeout=self.timeout,
) as _response:
await _response.read()
except (ssl.SSLError, aiohttp.ClientConnectorCertificateError, aiohttp.ClientSSLError) as ex:
Expand Down Expand Up @@ -135,6 +145,7 @@ async def post_request(
data=json.dumps(payload),
headers=headers,
ssl=False if self.insecure else True,
timeout=self.timeout,
) as _response:
if _response.status != 204:
await _response.read()
Expand All @@ -157,6 +168,7 @@ async def patch_request(self, uri: str, payload: Dict[str, Any], headers: Dict[s
data=json.dumps(payload),
headers=headers,
ssl=False if self.insecure else True,
timeout=self.timeout,
) as _response:
raw_data = await _response.read()
self.logger.debug(raw_data)
Expand All @@ -182,6 +194,7 @@ async def delete_request(self, uri: str, headers: Dict[str, str]):
uri,
headers=headers,
ssl=False if self.insecure else True,
timeout=self.timeout,
) as _response:
raw_data = await _response.read()
self.logger.debug(raw_data)
Expand Down
55 changes: 40 additions & 15 deletions src/badfish/helpers/parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import argparse

from badfish import __version__
from badfish.config import RETRIES
from badfish.config import RETRIES, TIMEOUT


def _positive_int(value):
try:
ivalue = int(value)
except ValueError:
raise argparse.ArgumentTypeError(f"{value!r} is not an integer")
if ivalue <= 0:
raise argparse.ArgumentTypeError(f"{value} must be a positive integer")
return ivalue


def create_parser():
Expand All @@ -11,11 +21,11 @@ def create_parser():
allow_abbrev=False,
)
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
parser.add_argument("-H", "--host", help="iDRAC host address")
parser.add_argument("-u", help="iDRAC username")
parser.add_argument("-p", help="iDRAC password")
parser.add_argument("-i", help="Path to iDRAC interfaces yaml", default=None)
parser.add_argument("-t", help="Type of host as defined on iDRAC interfaces yaml")
parser.add_argument("-H", "--host", help="BMC host address")
parser.add_argument("-u", help="BMC username")
parser.add_argument("-p", help="BMC password")
parser.add_argument("-i", help="Path to interfaces yaml", default=None)
parser.add_argument("-t", help="Type of host as defined on interfaces yaml")
parser.add_argument("-l", "--log", help="Optional argument for logging results to a file")
parser.add_argument(
"-o",
Expand All @@ -39,7 +49,7 @@ def create_parser():
parser.add_argument("--boot-to", help="Set next boot to one-shot boot to a specific device")
parser.add_argument(
"--boot-to-type",
help="Set next boot to one-shot boot to a specific type as defined on iDRAC interfaces yaml",
help="Set next boot to one-shot boot to a specific type as defined on interfaces yaml",
)
parser.add_argument(
"--boot-to-mac",
Expand Down Expand Up @@ -71,8 +81,16 @@ def create_parser():
help="Get current consumed watts on host(s)",
action="store_true",
)
parser.add_argument("--racreset", help="Flag for iDRAC reset", action="store_true")
parser.add_argument("--wait", help="Wait for iDRAC to be responsive after reset", action="store_true")
parser.add_argument(
"--racreset",
help="(Dell iDRAC) Flag for Dell iDRAC reset",
action="store_true",
)
parser.add_argument(
"--wait",
help="(Dell iDRAC) Wait for Dell iDRAC to be responsive after reset",
action="store_true",
)
parser.add_argument("--bmc-reset", help="Flag for BMC reset", action="store_true")
parser.add_argument(
"--factory-reset",
Expand Down Expand Up @@ -240,36 +258,43 @@ def create_parser():
help="Number of retries for executing actions.",
default=RETRIES,
)
parser.add_argument(
"--timeout",
help="Timeout in seconds for each REST API call (must be > 0).",
default=TIMEOUT,
type=_positive_int,
)
parser.add_argument(
"--insecure",
help="Disable SSL/TLS certificate verification (insecure, use only for testing)",
action="store_true",
)
parser.add_argument(
"--get-scp-targets",
help="Get allowable target values to export or import with iDRAC SCP. Choices=['Export', 'Import']",
help="(Dell iDRAC) Get allowable target values to export or import with iDRAC SCP."
" Choices=['Export', 'Import']",
choices=["Export", "Import"],
default="",
)
parser.add_argument(
"--scp-targets",
help="Comma separated targets which configs should be exported with iDRAC SCP.",
help="(Dell iDRAC) Comma separated targets which configs should be exported with Dell iDRAC SCP.",
default="ALL",
)
parser.add_argument(
"--scp-include-read-only",
help="Flag for including read only attributes in SCP export.",
help="(Dell iDRAC) Flag for including read only attributes in Dell iDRAC SCP export.",
action="store_true",
)
parser.add_argument(
"--export-scp",
help="Export system config using iDRAC SCP, argument specifies where file should be saved.",
help="(Dell iDRAC) Export system config using Dell iDRAC SCP, argument specifies where file should be saved.",
default="",
)
parser.add_argument(
"--import-scp",
help="Import system config using iDRAC SCP, argument specifies which JSON file contains config that should be "
"imported.",
help="(Dell iDRAC) Import system config using iDRAC SCP, argument specifies which JSON file"
" contains config that should be imported.",
default="",
)
parser.add_argument(
Expand Down
Loading
Loading