Showing preview only (1,131K chars total). Download the full file or copy to clipboard to get everything.
Repository: bmc-toolbox/bmclib
Branch: main
Commit: 3269f94932e9
Files: 219
Total size: 1.0 MB
Directory structure:
gitextract_jzsoh1mg/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── default.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── mergify.yml
│ └── workflows/
│ └── ci.yaml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── Makefile
├── README.md
├── bmc/
│ ├── bios.go
│ ├── bmc.go
│ ├── boot_device.go
│ ├── boot_device_test.go
│ ├── connection.go
│ ├── connection_test.go
│ ├── firmware.go
│ ├── firmware_test.go
│ ├── floppy.go
│ ├── floppy_test.go
│ ├── inventory.go
│ ├── inventory_test.go
│ ├── nmi.go
│ ├── nmi_test.go
│ ├── postcode.go
│ ├── postcode_test.go
│ ├── power.go
│ ├── power_test.go
│ ├── provider.go
│ ├── reset.go
│ ├── reset_test.go
│ ├── screenshot.go
│ ├── screenshot_test.go
│ ├── sel.go
│ ├── sel_test.go
│ ├── sol.go
│ ├── sol_test.go
│ ├── user.go
│ ├── user_test.go
│ ├── virtual_media.go
│ └── virtual_media_test.go
├── client.go
├── client_test.go
├── constants/
│ └── constants.go
├── doc.go
├── errors/
│ └── errors.go
├── examples/
│ ├── bios/
│ │ ├── doc.go
│ │ └── main.go
│ ├── create-users/
│ │ ├── doc.go
│ │ └── main.go
│ ├── floppy-image/
│ │ ├── doc.go
│ │ └── main.go
│ ├── homeassistant/
│ │ └── main.go
│ ├── install-firmware/
│ │ ├── doc.go
│ │ └── main.go
│ ├── inventory/
│ │ ├── doc.go
│ │ ├── main.go
│ │ └── output.json
│ ├── reset_bmc/
│ │ └── reset_bmc.go
│ ├── rpc/
│ │ └── main.go
│ ├── screenshot/
│ │ ├── doc.go
│ │ └── main.go
│ ├── sel/
│ │ └── main.go
│ ├── status/
│ │ ├── doc.go
│ │ └── main.go
│ └── virtualmedia/
│ ├── doc.go
│ └── main.go
├── filter.go
├── fixtures/
│ └── internal/
│ └── sum/
│ ├── ChangeBiosConfig
│ ├── ChangeBiosConfig-Changed
│ ├── ChangeBiosConfig-Changed-Reboot
│ ├── GetBIOSInfo
│ ├── GetBiosConfiguration
│ └── SetBiosConfiguration
├── go.mod
├── go.sum
├── internal/
│ ├── executor/
│ │ ├── errors.go
│ │ ├── executor.go
│ │ ├── executor_test.go
│ │ └── fake_executor.go
│ ├── helper/
│ │ ├── helper.go
│ │ └── helper_test.go
│ ├── httpclient/
│ │ ├── httpclient.go
│ │ └── httpclient_test.go
│ ├── ipmi/
│ │ └── ipmi.go
│ ├── redfishwrapper/
│ │ ├── bios.go
│ │ ├── bios_test.go
│ │ ├── boot_device.go
│ │ ├── client.go
│ │ ├── client_test.go
│ │ ├── firmware.go
│ │ ├── firmware_test.go
│ │ ├── fixtures/
│ │ │ ├── dell/
│ │ │ │ ├── bios.json
│ │ │ │ ├── manager.idrac.embedded.1.json
│ │ │ │ ├── managers.json
│ │ │ │ ├── serviceroot.json
│ │ │ │ ├── system.embedded.1.json
│ │ │ │ ├── system.embedded.1.virtualmedia.json
│ │ │ │ ├── systems.json
│ │ │ │ ├── virtualmedia_1.json
│ │ │ │ ├── virtualmedia_2.json
│ │ │ │ └── virtualmedia_collection.json
│ │ │ ├── managers.json
│ │ │ ├── managers_1.json
│ │ │ ├── serviceroot.json
│ │ │ ├── serviceroot_no_manager.json
│ │ │ ├── smc_1.14.0_serviceroot.json
│ │ │ ├── smc_1.14.0_systems.json
│ │ │ ├── smc_1.14.0_systems_1.json
│ │ │ ├── smc_1.9.0_serviceroot.json
│ │ │ ├── systems.json
│ │ │ ├── systems_1.json
│ │ │ ├── systems_1_no_bios.json
│ │ │ ├── systems_bios.json
│ │ │ ├── tasks/
│ │ │ │ ├── tasks_1_completed.json
│ │ │ │ ├── tasks_1_failed.json
│ │ │ │ ├── tasks_1_pending.json
│ │ │ │ ├── tasks_1_running.json
│ │ │ │ ├── tasks_1_scheduled.json
│ │ │ │ ├── tasks_1_starting.json
│ │ │ │ ├── tasks_1_unknown.json
│ │ │ │ └── tasks_2.json
│ │ │ ├── tasks.json
│ │ │ ├── taskservice.json
│ │ │ ├── updateservice_disabled.json
│ │ │ ├── updateservice_ok_response.json
│ │ │ ├── updateservice_unexpected_response.json
│ │ │ ├── updateservice_with_httppushuri.json
│ │ │ └── updateservice_with_multipart.json
│ │ ├── inventory.go
│ │ ├── inventory_collect.go
│ │ ├── inventory_collect_test.go
│ │ ├── main_test.go
│ │ ├── power.go
│ │ ├── sel.go
│ │ ├── system.go
│ │ ├── system_test.go
│ │ ├── task.go
│ │ ├── task_test.go
│ │ ├── virtual_media.go
│ │ └── virtual_media_test.go
│ ├── sum/
│ │ ├── sum.go
│ │ └── sum_test.go
│ └── utils.go
├── lint.mk
├── logging/
│ └── logging.go
├── option.go
└── providers/
├── asrockrack/
│ ├── asrockrack.go
│ ├── asrockrack_test.go
│ ├── firmware.go
│ ├── firmware_update.md
│ ├── fixtures/
│ │ └── E3C246D4I-NL/
│ │ └── sensors.json
│ ├── helpers.go
│ ├── helpers_test.go
│ ├── inventory.go
│ ├── inventory_test.go
│ ├── mock_test.go
│ ├── power.go
│ ├── user.go
│ └── user_test.go
├── dell/
│ ├── firmware.go
│ ├── firmware_test.go
│ ├── fixtures/
│ │ ├── serviceroot.json
│ │ ├── systems.json
│ │ ├── systems_embedded.1.json
│ │ ├── systems_embedded_no_manufacturer.1.json
│ │ └── systems_embedded_not_dell.1.json
│ ├── idrac.go
│ └── idrac_test.go
├── homeassistant/
│ └── homeassistant.go
├── intelamt/
│ ├── intelamt.go
│ └── intelamt_test.go
├── ipmitool/
│ ├── ipmitool.go
│ └── ipmitool_test.go
├── openbmc/
│ ├── firmware.go
│ └── openbmc.go
├── providers.go
├── redfish/
│ ├── fixtures/
│ │ └── v1/
│ │ ├── dell/
│ │ │ ├── entries.json
│ │ │ ├── job_delete_ok.json
│ │ │ ├── jobs.json
│ │ │ ├── logservices.json
│ │ │ ├── logservices.sel.json
│ │ │ ├── manager.idrac.embedded.1.json
│ │ │ ├── managers.json
│ │ │ └── selentries/
│ │ │ ├── 1.json
│ │ │ └── 2.json
│ │ ├── serviceroot.json
│ │ ├── systems.json
│ │ └── updateservice.json
│ ├── main_test.go
│ ├── redfish.go
│ ├── sel.go
│ ├── sel_test.go
│ └── user.go
├── rpc/
│ ├── doc.go
│ ├── experimental.go
│ ├── http.go
│ ├── http_test.go
│ ├── logging.go
│ ├── payload.go
│ ├── rpc.go
│ ├── rpc_test.go
│ └── signature.go
└── supermicro/
├── docs/
│ ├── x11.md
│ └── x12.md
├── errors.go
├── firmware.go
├── firmware_bios_test.go
├── fixtures/
│ └── serviceroot.json
├── floppy.go
├── supermicro.go
├── supermicro_test.go
├── types.go
├── x11.go
├── x11_firmware_bios.go
├── x11_firmware_bmc.go
├── x11_firmware_bmc_test.go
└── x12.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .devcontainer/Dockerfile
================================================
FROM mcr.microsoft.com/devcontainers/go:1-1.22-bullseye
RUN apt update
RUN apt install ipmitool -y
================================================
FILE: .devcontainer/devcontainer.json
================================================
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/go
{
"name": "Go",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
// "image": "mcr.microsoft.com/devcontainers/go:1-1.21-bullseye",
"build": {
"dockerfile": "Dockerfile"
},
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "go version",
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.makefile-tools",
"zxh404.vscode-proto3",
"humao.rest-client"
]
}
}
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
================================================
FILE: .github/ISSUE_TEMPLATE/default.md
================================================
Please don't forget to include the following information in your issue:
- The HW vendor impacted by this issue (if applicable)
- The HW model number, BMC firmware and/or BIOS versions impacted by this issue (if applicable)
- What version of bmclib exhibits this behavior (if applicable)
- Detailed steps to verify it
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## What does this PR implement/change/remove?
### Checklist
- [ ] Tests added
- [ ] Similar commits squashed
### The HW vendor this change applies to (if applicable)
### The HW model number, product name this change applies to (if applicable)
### The BMC firmware and/or BIOS versions that this change applies to (if applicable)
### What version of tooling - vendor specific or opensource does this change depend on (if applicable)
## Description for changelog/release notes
```
```
================================================
FILE: .github/mergify.yml
================================================
queue_rules:
- name: default
batch_size: 1
queue_conditions:
- base=main
- "#approved-reviews-by>=1"
- "#changes-requested-reviews-by=0"
- check-success='lint'
- check-success='test'
- label!=do-not-merge
- label=ready-to-merge
merge_conditions:
- base=main
- "#approved-reviews-by>=1"
- "#changes-requested-reviews-by=0"
- check-success='lint'
- check-success='test'
- label!=do-not-merge
- label=ready-to-merge
merge_method: merge
commit_message_template: |
{{ title }} (#{{ number }})
pull_request_rules:
- name: refactored queue action rule
conditions: []
actions:
queue:
merge_queue:
max_parallel_checks: 1
================================================
FILE: .github/workflows/ci.yaml
================================================
name: For each commit and PR
on:
push:
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
env:
CGO_ENABLED: 1
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Go
uses: actions/setup-go@v3
with:
go-version-file: go.mod
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
args: -v --config .golangci.yml --timeout=5m
version: latest
- name: make all-checks
run: make all-checks
test:
runs-on: ubuntu-latest
env:
CGO_ENABLED: 1
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Install Go
uses: actions/setup-go@v3
with:
go-version-file: go.mod
- name: make all-tests
run: make all-tests
- name: upload codecov
run: bash <(curl -s https://codecov.io/bash)
================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Swap
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
# vscode
*.code-workspace
# added by lint-install
out/
coverage.txt
================================================
FILE: .golangci.yml
================================================
govet:
auto-fix: true
linters-settings:
enable:
- fieldalignment
check-shadowing: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
golint:
min-confidence: 0
gocyclo:
min-complexity: 10
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
depguard:
list-type: blacklist
packages:
# logging is allowed only by logutils.Log, logrus
# is allowed to use only in logutils package
- github.com/sirupsen/logrus
misspell:
locale: US
auto-fix: true
lll:
line-length: 140
goimports:
local-prefixes: github.com/golangci/golangci-lint
gocritic:
auto-fix: true
enabled-tags:
- performance
- style
- experimental
disabled-checks:
- wrapperFunc
gofumpt:
extra-rules: true
auto-fix: true
wsl:
auto-fix: true
stylecheck:
auto-fix: true
linters:
enable:
- errcheck
- gosimple
- govet
- gofmt
- gocyclo
- ineffassign
- stylecheck
- deadcode
- staticcheck
- structcheck
- unused
- prealloc
- typecheck
- varcheck
# additional linters
- bodyclose
- gocritic
- whitespace
- wsl
- goimports
- golint
- misspell
- goerr113
- noctx
enable-all: false
disable-all: true
run:
skip-dirs:
issues:
exclude-rules:
- linters:
- gosec
text: "weak cryptographic primitive"
- linters:
- stylecheck
text: "ST1016"
exclude:
# Default excludes from `golangci-lint run --help` with EXC0002 removed
# EXC0001 errcheck: Almost all programs ignore errors on these functions and in most cases it's ok
- Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
# EXC0002 golint: Annoying issue about not having a comment. The rare codebase has such comments
# - (comment on exported (method|function|type|const)|should have( a package)? comment|comment should be of the form)
# EXC0003 golint: False positive when tests are defined in package 'test'
- func name will be used as test\.Test.* by other packages, and that stutters; consider calling this
# EXC0004 govet: Common false positives
- (possible misuse of unsafe.Pointer|should have signature)
# EXC0005 staticcheck: Developers tend to write in C-style with an explicit 'break' in a 'switch', so it's ok to ignore
- ineffective break statement. Did you mean to break out of the outer loop
# EXC0006 gosec: Too many false-positives on 'unsafe' usage
- Use of unsafe calls should be audited
# EXC0007 gosec: Too many false-positives for parametrized shell calls
- Subprocess launch(ed with variable|ing should be audited)
# EXC0008 gosec: Duplicated errcheck checks
- (G104|G307)
# EXC0009 gosec: Too many issues in popular repos
- (Expect directory permissions to be 0750 or less|Expect file permissions to be 0600 or less)
# EXC0010 gosec: False positive is triggered by 'src, err := ioutil.ReadFile(filename)'
- Potential file inclusion via variable
exclude-use-default: false
# golangci.com configuration
# https://github.com/golangci/golangci/wiki/Configuration
#service:
# golangci-lint-version: 1.15.x # use the fixed version to not introduce new linters unexpectedly
# prepare:
# - echo "here I can run custom commands, but no preparation needed for this repo"
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2022] [bmclib authors]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | cut -d":" -f2,3 | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}'
.PHONY: test
test: ## Run unit tests
go test -v -covermode=atomic -race ./...
.PHONY: cover
cover: ## Run unit tests with coverage report
go test -coverprofile=coverage.txt ./...
go tool cover -func=coverage.txt
.PHONY: all-tests
all-tests: test cover ## run all tests
.PHONY: all-checks
all-checks: lint ## run all formatters
go mod tidy
go vet ./...
-include lint.mk
================================================
FILE: README.md
================================================
# bmclib v2 - board management controller library
[](https://github.com/bmc-toolbox/bmclib/actions)
[](https://goreportcard.com/report/github.com/bmc-toolbox/bmclib/v2)
[](https://godoc.org/github.com/bmc-toolbox/bmclib/v2)
bmclib v2 is a library to abstract interacting with baseboard management controllers.
## Supported BMC interfaces.
- [Redfish](https://github.com/bmc-toolbox/bmclib/tree/main/providers/redfish)
- [IPMItool](https://github.com/bmc-toolbox/bmclib/tree/main/providers/ipmitool)
- [Intel AMT](https://github.com/bmc-toolbox/bmclib/tree/main/providers/intelamt)
- [Asrockrack](https://github.com/bmc-toolbox/bmclib/tree/main/providers/asrockrack)
- [RPC](providers/rpc/)
## Installation
```bash
go get github.com/bmc-toolbox/bmclib/v2
```
## Import
```go
import (
bmclib "github.com/bmc-toolbox/bmclib/v2"
)
```
### Usage
The snippet below connects to a BMC and retrieves the device hardware, firmware inventory.
```go
import (
bmclib "github.com/bmc-toolbox/bmclib/v2"
)
// setup logger
l := logrus.New()
l.Level = logrus.DebugLevel
logger := logrusr.New(l)
clientOpts := []bmclib.Option{bmclib.WithLogger(logger)}
// init client
client := bmclib.NewClient(*host, "admin", "hunter2", clientOpts...)
// open BMC session
err := client.Open(ctx)
if err != nil {
log.Fatal(err, "bmc login failed")
}
defer client.Close(ctx)
// retrieve inventory data
inventory, err := client.Inventory(ctx)
if err != nil {
l.Error(err)
}
b, err := json.MarshalIndent(inventory, "", " ")
if err != nil {
l.Error(err)
}
fmt.Println(string(b))
```
More sample code can be found in [examples](./examples/)
## BMC connections
bmclib performs queries on BMCs using [multiple `drivers`](https://github.com/bmc-toolbox/bmclib/blob/main/bmc/connection.go#L30),
these `drivers` are the various services exposed by a BMC - `redfish` `IPMI` `SSH` and `vendor API` which is basically a custom vendor API endpoint.
The bmclib client determines which driver to use for an action like `Power cycle` or `Create user`
based on its availability or through a compatibility test (when enabled).
When querying multiple BMCs through bmclib its often useful to to limit the BMCs and
drivers that bmclib will attempt to use to connect, the options to limit or filter
out BMCs are described below,
Query just using the `redfish` endpoint.
```go
cl := bmclib.NewClient("192.168.1.1", "admin", "hunter2")
cl.Registry.Drivers = cl.Registry.Using("redfish")
```
Query using the `redfish` endpoint and fall back to `IPMI`
```go
client := bmclib.NewClient("192.168.1.1", "admin", "hunter2")
// overwrite registered drivers by appending Redfish, IPMI drivers in order
drivers := append(registrar.Drivers{}, bmcClient.Registry.Using("redfish")...)
drivers = append(drivers, bmcClient.Registry.Using("ipmi")...)
client.Registry.Drivers = driver
```
Filter drivers to query based on compatibility, this will attempt to check if the driver is
[compatible](https://github.com/bmc-toolbox/bmclib/blob/main/providers/redfish/redfish.go#L70)
ideally, this method should be invoked when the client is ready to perform a BMC action.
```go
client := bmclib.NewClient("192.168.1.1", "admin", "hunter2")
client.Registry.Drivers = cl.Registry.FilterForCompatible(ctx)
```
Ignore the Redfish endpoint completely on BMCs running a specific Redfish version.
Note: this version should match the one returned through `curl -k "https://<BMC IP>/redfish/v1" | jq .RedfishVersion`
```go
opt := bmclib.WithRedfishVersionsNotCompatible([]string{"1.5.0"})
client := bmclib.NewClient("192.168.1.1", "admin", "hunter2", opt...)
cl.Registry.Drivers = cl.Registry.FilterForCompatible(ctx)
```
## Timeouts
bmclib can be configured to apply timeouts to BMC interactions. The following options are available.
**Total max timeout only** - The total time bmclib will wait for all BMC interactions to complete. This is specified using a single `context.WithTimeout` or `context.WithDeadline` that is passed to all method call. With this option, the per provider; per interaction timeout is calculated by the total max timeout divided by the number of providers (currently there are 4 providers).
```go
cl := bmclib.NewClient(host, user, pass, bmclib.WithLogger(log))
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err = cl.Open(ctx); err != nil {
return(err)
}
defer cl.Close(ctx)
state, err := cl.GetPowerState(ctx)
```
**Total max timeout and a per provider; per interaction timeout** - The total time bmclib will wait for all BMC interactions to complete. This is specified using a single `context.WithTimeout` or `context.WithDeadline` that is passed to all method call. This is honored above all timeouts. The per provider; per interaction timeout is specified using `bmclib.WithPerProviderTimeout` in the Client constructor.
```go
cl := bmclib.NewClient(host, user, pass, bmclib.WithLogger(log), bmclib.WithPerProviderTimeout(15*time.Second))
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
if err = cl.Open(ctx); err != nil {
return(err)
}
defer cl.Close(ctx)
state, err := cl.GetPowerState(ctx)
```
**Per provider; per interaction timeout. No total max timeout** - The time bmclib will wait for a specific provider to complete. This is specified using `bmclib.WithPerProviderTimeout` in the Client constructor.
```go
cl := bmclib.NewClient(host, user, pass, bmclib.WithLogger(log), bmclib.WithPerProviderTimeout(15*time.Second))
ctx := context.Background()
if err = cl.Open(ctx); err != nil {
return(err)
}
defer cl.Close(ctx)
state, err := cl.GetPowerState(ctx)
```
**Default timeout** - If no timeout is specified with a context or with `bmclib.WithPerProviderTimeout` the default is used. 30 seconds per provider; per interaction.
```go
cl := bmclib.NewClient(host, user, pass, bmclib.WithLogger(log))
ctx := context.Background()
if err = cl.Open(ctx); err != nil {
return(err)
}
defer cl.Close(ctx)
state, err := cl.GetPowerState(ctx)
```
## Filtering
The `bmclib.Client` can be configured to filter BMC calls based on a few different criteria. Filtering modifies the order and/or the number of providers for BMC calls. This filtering can be permanent or on a one-time basis.
All providers are stored in a registry (see [`Client.Registry`](https://github.com/bmc-toolbox/bmclib/blob/b5cdfa3ffe026d3cc3257953abe3234b278ca20a/client.go#L29)) and the default order for providers in the registry is `ipmitool`, `asrockrack`, `gofish`, `IntelAMT`. The default order is defined [here](https://github.com/bmc-toolbox/bmclib/blob/b5cdfa3ffe026d3cc3257953abe3234b278ca20a/client.go#L152).
### Permanent Filtering
Permanent filtering modifies the order and/or the number of providers for BMC calls for all client methods (for example: `Open`, `SetPowerState`, etc) calls.
```go
cl := bmclib.NewClient(host, user, pass)
// This will modify the order for all subsequent BMC calls
cl.Registry.Drivers = cl.Registry.PreferDriver("gofish")
if err := cl.Open(ctx); err != nil {
return(err)
}
```
The following permanent filters are available:
- `cl.Registry.PreferDriver("gofish")` - This moves the `gofish` provider to be the first provider in the registry.
- `cl.Registry.Supports(providers.FeaturePowerSet)` - This removes any provider from the registry that does not support the setting the power state.
- `cl.Registry.Using("redfish")` - This removes any provider from the registry that does not support the `redfish` protocol.
- `cl.Registry.For("gofish")` - This removes any provider from the registry that is not the `gofish` provider.
- `cl.Registry.PreferProtocol("redfish")` - This moves any provider that implements the `redfish` protocol to the beginning of the registry.
### One-time Filtering
One-time filtering modifies the order and/or the number of providers for BMC calls only for a single method call.
```Go
cl := bmclib.NewClient(host, user, pass)
// This will modify the order for only this BMC call
if err := cl.PreferProvider("gofish").Open(ctx); err != nil {
return(err)
}
```
The following one-time filters are available:
- `cl.PreferProtocol("gofish").GetPowerState(ctx)` - This moves the `gofish` provider to be the first provider in the registry.
- `cl.Supports(providers.FeaturePowerSet).GetPowerState(ctx)` - This removes any provider from the registry that does not support the setting the power state.
- `cl.Using("redfish").GetPowerState(ctx)` - This removes any provider from the registry that does not support the `redfish` protocol.
- `cl.For("gofish").GetPowerState(ctx)` - This removes any provider from the registry that is not the `gofish` provider.
- `cl.PreferProtocol("redfish").GetPowerState(ctx)` - This moves any provider that implements the `redfish` protocol to the beginning of the registry.
### Tracing
To collect trace telemetry, set the `WithTraceProvider()` option on the client
which results in trace spans being collected for each client method.
```go
cl := bmclib.NewClient(
host,
user,
pass,
bmclib.WithLogger(log),
bmclib.WithTracerProvider(otel.GetTracerProvider()),
)
```
## Versions
The current bmclib version is `v2` and is being developed on the `main` branch.
The previous bmclib version is in maintenance mode and can be found here [v1](https://github.com/bmc-toolbox/bmclib/v1).
## Go version in `go.mod`
As a library we will only bump the version of Go in the `go.mod` file when there are required dependencies in bmclib that necessitate
a version bump. When consuming bmclib in your project, we recommend always building with the latest Go version but this
should be in your hands as a user as much as possible.
## Acknowledgments
bmclib v2 interfaces with Redfish on BMCs through the Gofish library https://github.com/stmcginnis/gofish
bmclib was originally developed for [Booking.com](http://www.booking.com). With approval from [Booking.com](http://www.booking.com),
the code and specification were generalized and published as Open Source on github, for which the authors would like to express their gratitude.
### Authors
- [Joel Rebello](https://github.com/joelrebel)
- [Jacob Weinstock](https://github.com/jacobweinstock)
================================================
FILE: bmc/bios.go
================================================
package bmc
import (
"context"
"fmt"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
type BiosConfigurationGetter interface {
GetBiosConfiguration(ctx context.Context) (biosConfig map[string]string, err error)
}
type biosConfigurationGetterProvider struct {
name string
BiosConfigurationGetter
}
type BiosConfigurationSetter interface {
SetBiosConfiguration(ctx context.Context, biosConfig map[string]string) (err error)
SetBiosConfigurationFromFile(ctx context.Context, cfg string) (err error)
}
type biosConfigurationSetterProvider struct {
name string
BiosConfigurationSetter
}
type BiosConfigurationResetter interface {
ResetBiosConfiguration(ctx context.Context) (err error)
}
type biosConfigurationResetterProvider struct {
name string
BiosConfigurationResetter
}
func biosConfiguration(ctx context.Context, generic []biosConfigurationGetterProvider) (biosConfig map[string]string, metadata Metadata, err error) {
metadata = newMetadata()
Loop:
for _, elem := range generic {
if elem.BiosConfigurationGetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
biosConfig, vErr := elem.GetBiosConfiguration(ctx)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue
}
metadata.SuccessfulProvider = elem.name
return biosConfig, metadata, nil
}
}
return biosConfig, metadata, multierror.Append(err, errors.New("failure to get bios configuration"))
}
func setBiosConfiguration(ctx context.Context, generic []biosConfigurationSetterProvider, biosConfig map[string]string) (metadata Metadata, err error) {
metadata = newMetadata()
Loop:
for _, elem := range generic {
if elem.BiosConfigurationSetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
vErr := elem.SetBiosConfiguration(ctx, biosConfig)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue
}
metadata.SuccessfulProvider = elem.name
return metadata, nil
}
}
return metadata, multierror.Append(err, errors.New("failure to set bios configuration"))
}
func setBiosConfigurationFromFile(ctx context.Context, generic []biosConfigurationSetterProvider, cfg string) (metadata Metadata, err error) {
metadata = newMetadata()
Loop:
for _, elem := range generic {
if elem.BiosConfigurationSetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
vErr := elem.SetBiosConfigurationFromFile(ctx, cfg)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue
}
metadata.SuccessfulProvider = elem.name
return metadata, nil
}
}
return metadata, multierror.Append(err, errors.New("failure to set bios configuration from file"))
}
func resetBiosConfiguration(ctx context.Context, generic []biosConfigurationResetterProvider) (metadata Metadata, err error) {
metadata = newMetadata()
Loop:
for _, elem := range generic {
if elem.BiosConfigurationResetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
vErr := elem.ResetBiosConfiguration(ctx)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue
}
metadata.SuccessfulProvider = elem.name
return metadata, nil
}
}
return metadata, multierror.Append(err, errors.New("failure to reset bios configuration"))
}
func GetBiosConfigurationInterfaces(ctx context.Context, generic []interface{}) (biosConfig map[string]string, metadata Metadata, err error) {
implementations := make([]biosConfigurationGetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := biosConfigurationGetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case BiosConfigurationGetter:
temp.BiosConfigurationGetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a BiosConfigurationGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return biosConfig, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no BiosConfigurationGetter implementations found"),
),
)
}
return biosConfiguration(ctx, implementations)
}
func SetBiosConfigurationInterfaces(ctx context.Context, generic []interface{}, biosConfig map[string]string) (metadata Metadata, err error) {
implementations := make([]biosConfigurationSetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := biosConfigurationSetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case BiosConfigurationSetter:
temp.BiosConfigurationSetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a BiosConfigurationSetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no BiosConfigurationSetter implementations found"),
),
)
}
return setBiosConfiguration(ctx, implementations, biosConfig)
}
func SetBiosConfigurationFromFileInterfaces(ctx context.Context, generic []interface{}, cfg string) (metadata Metadata, err error) {
implementations := make([]biosConfigurationSetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := biosConfigurationSetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case BiosConfigurationSetter:
temp.BiosConfigurationSetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a BiosConfigurationSetterFromFile implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no BiosConfigurationSetterFromFile implementations found"),
),
)
}
return setBiosConfigurationFromFile(ctx, implementations, cfg)
}
func ResetBiosConfigurationInterfaces(ctx context.Context, generic []interface{}) (metadata Metadata, err error) {
implementations := make([]biosConfigurationResetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := biosConfigurationResetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case BiosConfigurationResetter:
temp.BiosConfigurationResetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a BiosConfigurationResetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no BiosConfigurationResetter implementations found"),
),
)
}
return resetBiosConfiguration(ctx, implementations)
}
================================================
FILE: bmc/bmc.go
================================================
package bmc
import (
"strings"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
// Metadata represents details about a bmc method
type Metadata struct {
// SuccessfulProvider is the name of the provider that successfully executed
SuccessfulProvider string
// ProvidersAttempted is a slice of all providers that were attempt to execute
ProvidersAttempted []string
// SuccessfulOpenConns is a slice of provider names that were opened successfully
SuccessfulOpenConns []string
// SuccessfulCloseConns is a slice of provider names that were closed successfully
SuccessfulCloseConns []string
// FailedProviderDetail holds the failed providers error messages for called methods
FailedProviderDetail map[string]string
}
func newMetadata() Metadata {
return Metadata{
FailedProviderDetail: make(map[string]string),
}
}
func (m *Metadata) RegisterSpanAttributes(host string, span trace.Span) {
span.SetAttributes(attribute.String("host", host))
span.SetAttributes(attribute.String("successful-provider", m.SuccessfulProvider))
span.SetAttributes(
attribute.String("successful-open-conns", strings.Join(m.SuccessfulOpenConns, ",")),
)
span.SetAttributes(
attribute.String("successful-close-conns", strings.Join(m.SuccessfulCloseConns, ",")),
)
span.SetAttributes(
attribute.String("attempted-providers", strings.Join(m.ProvidersAttempted, ",")),
)
for p, e := range m.FailedProviderDetail {
span.SetAttributes(
attribute.String("provider-errs-"+p, e),
)
}
}
================================================
FILE: bmc/boot_device.go
================================================
package bmc
import (
"context"
"fmt"
"time"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
type BootDeviceType string
const (
BootDeviceTypeBIOS BootDeviceType = "bios"
BootDeviceTypeCDROM BootDeviceType = "cdrom"
BootDeviceTypeDiag BootDeviceType = "diag"
BootDeviceTypeFloppy BootDeviceType = "floppy"
BootDeviceTypeDisk BootDeviceType = "disk"
BootDeviceTypeNone BootDeviceType = "none"
BootDeviceTypePXE BootDeviceType = "pxe"
BootDeviceTypeRemoteDrive BootDeviceType = "remote_drive"
BootDeviceTypeSDCard BootDeviceType = "sd_card"
BootDeviceTypeUSB BootDeviceType = "usb"
BootDeviceTypeUtil BootDeviceType = "utilities"
BootDeviceUefiHTTP BootDeviceType = "uefi_http"
)
// BootDeviceSetter sets the next boot device for a machine
type BootDeviceSetter interface {
BootDeviceSet(ctx context.Context, bootDevice string, setPersistent, efiBoot bool) (ok bool, err error)
}
// BootDeviceOverrideGetter gets boot override settings for a machine
type BootDeviceOverrideGetter interface {
BootDeviceOverrideGet(ctx context.Context) (override BootDeviceOverride, err error)
}
// bootDeviceProviders is an internal struct to correlate an implementation/provider and its name
type bootDeviceProviders struct {
name string
bootDeviceSetter BootDeviceSetter
}
// bootOverrideProvider is an internal struct to correlate an implementation/provider and its name
type bootOverrideProvider struct {
name string
bootOverrideGetter BootDeviceOverrideGetter
}
type BootDeviceOverride struct {
IsPersistent bool
IsEFIBoot bool
Device BootDeviceType
}
// setBootDevice sets the next boot device.
//
// setPersistent persists the next boot device.
// efiBoot sets up the device to boot off UEFI instead of legacy.
func setBootDevice(ctx context.Context, timeout time.Duration, bootDevice string, setPersistent, efiBoot bool, b []bootDeviceProviders) (ok bool, metadata Metadata, err error) {
metadataLocal := newMetadata()
for _, elem := range b {
if elem.bootDeviceSetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return false, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
ok, setErr := elem.bootDeviceSetter.BootDeviceSet(ctx, bootDevice, setPersistent, efiBoot)
if setErr != nil {
err = multierror.Append(err, errors.WithMessagef(setErr, "provider: %v", elem.name))
metadataLocal.FailedProviderDetail[elem.name] = setErr.Error()
continue
}
if !ok {
err = multierror.Append(err, fmt.Errorf("provider: %v, failed to set boot device", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return ok, metadataLocal, nil
}
}
return ok, metadataLocal, multierror.Append(err, errors.New("failed to set boot device"))
}
// SetBootDeviceFromInterfaces identifies implementations of the BootDeviceSetter interface and passes the found implementations to the setBootDevice() wrapper
func SetBootDeviceFromInterfaces(ctx context.Context, timeout time.Duration, bootDevice string, setPersistent, efiBoot bool, generic []interface{}) (ok bool, metadata Metadata, err error) {
bdSetters := make([]bootDeviceProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := bootDeviceProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case BootDeviceSetter:
temp.bootDeviceSetter = p
bdSetters = append(bdSetters, temp)
default:
e := fmt.Sprintf("not a BootDeviceSetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(bdSetters) == 0 {
return ok, metadata, multierror.Append(err, errors.New("no BootDeviceSetter implementations found"))
}
return setBootDevice(ctx, timeout, bootDevice, setPersistent, efiBoot, bdSetters)
}
// getBootDeviceOverride gets the boot device override settings for the given provider,
// and updates the given metadata with provider attempts and errors.
func getBootDeviceOverride(
ctx context.Context,
timeout time.Duration,
provider *bootOverrideProvider,
metadata *Metadata,
) (override BootDeviceOverride, ok bool, err error) {
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return override, ok, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, provider.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
override, err = provider.bootOverrideGetter.BootDeviceOverrideGet(ctx)
if err != nil {
metadata.FailedProviderDetail[provider.name] = err.Error()
return override, ok, nil
}
metadata.SuccessfulProvider = provider.name
return override, true, nil
}
}
// GetBootDeviceOverrideFromInterface will get boot device override settings from the first successful
// call to a BootDeviceOverrideGetter in the array of providers.
func GetBootDeviceOverrideFromInterface(
ctx context.Context,
timeout time.Duration,
providers []interface{},
) (override BootDeviceOverride, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range providers {
if elem == nil {
continue
}
switch p := elem.(type) {
case BootDeviceOverrideGetter:
provider := &bootOverrideProvider{name: getProviderName(elem), bootOverrideGetter: p}
override, ok, getErr := getBootDeviceOverride(ctx, timeout, provider, &metadata)
if getErr != nil || ok {
return override, metadata, getErr
}
default:
e := fmt.Errorf("not a BootDeviceOverrideGetter implementation: %T", p)
err = multierror.Append(err, e)
}
}
if len(metadata.ProvidersAttempted) == 0 {
err = multierror.Append(err, errors.New("no BootDeviceOverrideGetter implementations found"))
} else {
err = multierror.Append(err, errors.New("failed to get boot device override settings"))
}
return override, metadata, err
}
================================================
FILE: bmc/boot_device_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"fmt"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
"github.com/stretchr/testify/assert"
)
type bootDeviceTester struct {
MakeNotOK bool
MakeErrorOut bool
}
func (b *bootDeviceTester) BootDeviceSet(ctx context.Context, bootDevice string, setPersistent, efiBoot bool) (ok bool, err error) {
if b.MakeErrorOut {
return ok, errors.New("boot device set failed")
}
if b.MakeNotOK {
return false, nil
}
return true, nil
}
func (b *bootDeviceTester) Name() string {
return "test provider"
}
func TestSetBootDevice(t *testing.T) {
testCases := map[string]struct {
bootDevice string
makeErrorOut bool
makeNotOk bool
want bool
err error
ctxTimeout time.Duration
}{
"success": {bootDevice: "pxe", want: true},
"not ok return": {bootDevice: "pxe", want: false, makeNotOk: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider, failed to set boot device"), errors.New("failed to set boot device")}}},
"error": {bootDevice: "pxe", want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider: boot device set failed"), errors.New("failed to set boot device")}}},
"error context timeout": {bootDevice: "pxe", want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := bootDeviceTester{MakeErrorOut: tc.makeErrorOut, MakeNotOK: tc.makeNotOk}
expectedResult := tc.want
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := setBootDevice(ctx, 0, tc.bootDevice, false, false, []bootDeviceProviders{{"test provider", &testImplementation}})
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestSetBootDeviceFromInterfaces(t *testing.T) {
testCases := map[string]struct {
bootDevice string
err error
badImplementation bool
want bool
withName bool
}{
"success": {bootDevice: "pxe", want: true},
"success with metadata": {bootDevice: "pxe", want: true, withName: true},
"no implementations found": {bootDevice: "pxe", want: false, badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a BootDeviceSetter implementation: *struct {}"), errors.New("no BootDeviceSetter implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := bootDeviceTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := tc.want
result, metadata, err := SetBootDeviceFromInterfaces(context.Background(), 0, tc.bootDevice, false, false, generic)
if err != nil {
diff := cmp.Diff(tc.err.Error(), err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withName {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
type mockBootDeviceOverrideGetter struct {
overrideReturn BootDeviceOverride
errReturn error
}
func (m *mockBootDeviceOverrideGetter) Name() string {
return "Mock"
}
func (m *mockBootDeviceOverrideGetter) BootDeviceOverrideGet(_ context.Context) (BootDeviceOverride, error) {
return m.overrideReturn, m.errReturn
}
func TestBootDeviceOverrideGet(t *testing.T) {
successOverride := BootDeviceOverride{
IsPersistent: false,
IsEFIBoot: true,
Device: BootDeviceTypeDisk,
}
successMetadata := &Metadata{
SuccessfulProvider: "Mock",
ProvidersAttempted: []string{"Mock"},
SuccessfulOpenConns: nil,
SuccessfulCloseConns: []string(nil),
FailedProviderDetail: map[string]string{},
}
mixedMetadata := &Metadata{
SuccessfulProvider: "Mock",
ProvidersAttempted: []string{"Mock", "Mock"},
SuccessfulOpenConns: nil,
SuccessfulCloseConns: []string(nil),
FailedProviderDetail: map[string]string{"Mock": "foo-failure"},
}
failMetadata := &Metadata{
SuccessfulProvider: "",
ProvidersAttempted: []string{"Mock"},
SuccessfulOpenConns: nil,
SuccessfulCloseConns: []string(nil),
FailedProviderDetail: map[string]string{"Mock": "foo-failure"},
}
emptyMetadata := &Metadata{
FailedProviderDetail: make(map[string]string),
}
testCases := []struct {
name string
hasCanceledContext bool
expectedErrorMsg string
expectedMetadata *Metadata
expectedOverride BootDeviceOverride
getters []interface{}
}{
{
name: "success",
expectedMetadata: successMetadata,
expectedOverride: successOverride,
getters: []interface{}{
&mockBootDeviceOverrideGetter{overrideReturn: successOverride},
},
},
{
name: "multiple getters",
expectedMetadata: mixedMetadata,
expectedOverride: successOverride,
getters: []interface{}{
"not a getter",
&mockBootDeviceOverrideGetter{errReturn: fmt.Errorf("foo-failure")},
&mockBootDeviceOverrideGetter{overrideReturn: successOverride},
},
},
{
name: "error",
expectedMetadata: failMetadata,
expectedErrorMsg: "failed to get boot device override settings",
getters: []interface{}{
&mockBootDeviceOverrideGetter{errReturn: fmt.Errorf("foo-failure")},
},
},
{
name: "nil BootDeviceOverrideGetters",
expectedMetadata: emptyMetadata,
expectedErrorMsg: "no BootDeviceOverrideGetter implementations found",
},
{
name: "nil BootDeviceOverrideGetter",
expectedMetadata: emptyMetadata,
expectedErrorMsg: "no BootDeviceOverrideGetter implementations found",
getters: []interface{}{nil},
},
{
name: "with canceled context",
hasCanceledContext: true,
expectedMetadata: emptyMetadata,
expectedErrorMsg: "context canceled",
getters: []interface{}{
&mockBootDeviceOverrideGetter{},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if testCase.hasCanceledContext {
cancel()
}
override, metadata, err := GetBootDeviceOverrideFromInterface(ctx, 0, testCase.getters)
if testCase.expectedErrorMsg != "" {
assert.ErrorContains(t, err, testCase.expectedErrorMsg)
} else {
assert.Nil(t, err)
}
assert.Equal(t, testCase.expectedOverride, override)
assert.Equal(t, testCase.expectedMetadata, &metadata)
})
}
}
================================================
FILE: bmc/connection.go
================================================
package bmc
import (
"context"
"fmt"
"sync"
"time"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// Opener interface for opening a connection to a BMC
type Opener interface {
Open(ctx context.Context) error
}
// Closer interface for closing a connection to a BMC
type Closer interface {
Close(ctx context.Context) error
}
// connectionProviders is an internal struct to correlate an implementation/provider and its name
type connectionProviders struct {
name string
closer Closer
}
// OpenConnectionFromInterfaces will try all opener interfaces and remove failed ones.
// The reason failed ones need to be removed is so that when other methods are called (like powerstate)
// implementations that have connections wont nil pointer error when their connection fails.
func OpenConnectionFromInterfaces(ctx context.Context, timeout time.Duration, providers []interface{}) (opened []interface{}, metadata Metadata, err error) {
metadata = newMetadata()
// Return immediately if the context is done.
select {
case <-ctx.Done():
return nil, metadata, multierror.Append(err, ctx.Err())
default:
}
// Create a context with the specified timeout. This is done for backward compatibility but
// we should consider removing the timeout parameter alltogether given the context will
// container the timeout.
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
// result facilitates communication of data between the concurrent opener goroutines and
// the the parent goroutine.
type result struct {
ProviderName string
Opener Opener
Err error
}
// Create a channel to communicate results between opener goroutines and the parent goroutine.
results := make(chan result)
// Use a WaitGroup to control closing of the results channel when all opener goroutines finish.
var wg sync.WaitGroup
// For every provider, launch a goroutine that attempts to open a connection and report
// back via the results channel what happened.
for _, elem := range providers {
if elem == nil {
continue
}
switch p := elem.(type) {
case Opener:
providerName := getProviderName(elem)
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, providerName)
wg.Add(1)
go func(provider Opener, providerName string) {
defer wg.Done()
res := result{ProviderName: providerName, Opener: provider}
if err := provider.Open(ctx); err != nil {
res.Err = errors.WithMessagef(err, "provider: %v", providerName)
}
results <- res
}(p, providerName)
default:
err = multierror.Append(err, fmt.Errorf("not a Opener implementation: %T", p))
}
}
// Launch the goroutine to close the results channel ensuring we can exit the for-range over
// the results channel below.
go func() { wg.Wait(); close(results) }()
// Gather and handle results from the opener goroutines.
for res := range results {
if res.Err != nil {
err = multierror.Append(err, res.Err)
metadata.FailedProviderDetail[res.ProviderName] = res.Err.Error()
continue
}
opened = append(opened, res.Opener)
metadata.SuccessfulOpenConns = append(metadata.SuccessfulOpenConns, res.ProviderName)
}
if len(opened) == 0 {
return nil, metadata, multierror.Append(err, errors.New("no Opener implementations found"))
}
return opened, metadata, nil
}
// closeConnection closes a connection to a BMC, trying all interface implementations passed in
func closeConnection(ctx context.Context, c []connectionProviders) (metadata Metadata, err error) {
metadata = newMetadata()
var connClosed bool
for _, elem := range c {
if elem.closer == nil {
continue
}
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
closeErr := elem.closer.Close(ctx)
if closeErr != nil {
err = multierror.Append(err, errors.WithMessagef(closeErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = closeErr.Error()
continue
}
connClosed = true
metadata.SuccessfulCloseConns = append(metadata.SuccessfulCloseConns, elem.name)
}
if connClosed {
return metadata, nil
}
return metadata, multierror.Append(err, errors.New("failed to close connection"))
}
// CloseConnectionFromInterfaces identifies implementations of the Closer() interface and and passes the found implementations to the closeConnection() wrapper
func CloseConnectionFromInterfaces(ctx context.Context, generic []interface{}) (metadata Metadata, err error) {
metadata = newMetadata()
closers := make([]connectionProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := connectionProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case Closer:
temp.closer = p
closers = append(closers, temp)
default:
e := fmt.Sprintf("not a Closer implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(closers) == 0 {
return metadata, multierror.Append(err, errors.New("no Closer implementations found"))
}
return closeConnection(ctx, closers)
}
================================================
FILE: bmc/connection_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
"go.uber.org/goleak"
)
type connTester1 struct {
MakeErrorOut bool
}
func (r *connTester1) Open(ctx context.Context) (err error) {
if r.MakeErrorOut {
return errors.New("open connection failed")
}
return nil
}
func (r *connTester1) Close(ctx context.Context) (err error) {
if r.MakeErrorOut {
return errors.New("close connection failed")
}
return nil
}
func (p *connTester1) Name() string {
return "test provider"
}
type connTester2 struct{}
func (r *connTester2) Open(ctx context.Context) (err error) {
<-ctx.Done()
return nil
}
func (r *connTester2) Close(ctx context.Context) (err error) {
return nil
}
func (p *connTester2) Name() string {
return "test provider 2"
}
func TestOpenConnectionFromInterfaces(t *testing.T) {
testCases := map[string]struct {
err error
makeErrorOut bool
badImplementation bool
withMetadata bool
withMultipleProviders bool
ctxTimeout time.Duration
}{
"success": {},
"success with metadata": {withMetadata: true},
"error context deadline": {err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded"), errors.New("no Opener implementations found")}}, ctxTimeout: time.Nanosecond * 1},
"error failed open": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider: open connection failed"), errors.New("no Opener implementations found")}}},
"no implementations found": {badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a Opener implementation: *struct {}"), errors.New("no Opener implementations found")}}},
"multiple providers attempted": {withMultipleProviders: true},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
defer goleak.VerifyNone(t)
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = append(generic, &badImplementation)
} else {
testImplementation := &connTester1{MakeErrorOut: tc.makeErrorOut}
generic = append(generic, testImplementation)
}
if tc.withMultipleProviders {
generic = append(generic, &connTester2{})
}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx := context.Background()
opened, metadata, err := OpenConnectionFromInterfaces(ctx, tc.ctxTimeout, generic)
if err != nil {
if tc.err != nil {
if diff := cmp.Diff(err.Error(), tc.err.Error()); diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
expected := []interface{}{&connTester1{}}
if tc.withMultipleProviders {
expected = append(expected, &connTester2{})
}
if diff := cmp.Diff(opened, expected); diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulOpenConns, []string{"test provider"}); diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestCloseConnection(t *testing.T) {
testCases := map[string]struct {
makeErrorOut bool
err error
ctxTimeout time.Duration
}{
"success": {},
"error context deadline": {err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
"error": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider: close connection failed"), errors.New("failed to close connection")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := connTester1{MakeErrorOut: tc.makeErrorOut}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
_, err := closeConnection(ctx, []connectionProviders{{"test provider", &testImplementation}})
if err != nil {
diff := cmp.Diff(tc.err.Error(), err.Error())
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestCloseConnectionFromInterfaces(t *testing.T) {
testCases := map[string]struct {
err error
badImplementation bool
withMetadata bool
}{
"success": {},
"success with metadata": {withMetadata: true},
"no implementations found": {badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a Closer implementation: *struct {}"), errors.New("no Closer implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := connTester1{}
generic = []interface{}{&testImplementation}
}
metadata, err := CloseConnectionFromInterfaces(context.Background(), generic)
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulCloseConns, []string{"test provider"}); diff != "" {
t.Fatal(diff)
}
}
})
}
}
================================================
FILE: bmc/firmware.go
================================================
package bmc
import (
"context"
"fmt"
"io"
"os"
"github.com/bmc-toolbox/bmclib/v2/constants"
bconsts "github.com/bmc-toolbox/bmclib/v2/constants"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// FirmwareInstaller defines an interface to upload and initiate a firmware install
type FirmwareInstaller interface {
// FirmwareInstall uploads firmware update payload to the BMC returning the task ID
//
// parameters:
// component - the component slug for the component update being installed.
// operationsApplyTime - one of the OperationApplyTime constants
// forceInstall - purge the install task queued/scheduled firmware install BMC task (if any).
// reader - the io.reader to the firmware update file.
//
// return values:
// taskID - A taskID is returned if the update process on the BMC returns an identifier for the update process.
FirmwareInstall(ctx context.Context, component string, operationApplyTime string, forceInstall bool, reader io.Reader) (taskID string, err error)
}
// firmwareInstallerProvider is an internal struct to correlate an implementation/provider and its name
type firmwareInstallerProvider struct {
name string
FirmwareInstaller
}
// firmwareInstall uploads and initiates firmware update for the component
func firmwareInstall(ctx context.Context, component, operationApplyTime string, forceInstall bool, reader io.Reader, generic []firmwareInstallerProvider) (taskID string, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range generic {
if elem.FirmwareInstaller == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return taskID, metadata, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
taskID, vErr := elem.FirmwareInstall(ctx, component, operationApplyTime, forceInstall, reader)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = err.Error()
continue
}
metadata.SuccessfulProvider = elem.name
return taskID, metadata, nil
}
}
return taskID, metadata, multierror.Append(err, errors.New("failure in FirmwareInstall"))
}
// FirmwareInstallFromInterfaces identifies implementations of the FirmwareInstaller interface and passes the found implementations to the firmwareInstall() wrapper
func FirmwareInstallFromInterfaces(ctx context.Context, component, operationApplyTime string, forceInstall bool, reader io.Reader, generic []interface{}) (taskID string, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]firmwareInstallerProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := firmwareInstallerProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FirmwareInstaller:
temp.FirmwareInstaller = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a FirmwareInstaller implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return taskID, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no FirmwareInstaller implementations found"),
),
)
}
return firmwareInstall(ctx, component, operationApplyTime, forceInstall, reader, implementations)
}
// Note: this interface is to be deprecated in favour of a more generic FirmwareTaskVerifier.
//
// FirmwareInstallVerifier defines an interface to check firmware install status
type FirmwareInstallVerifier interface {
// FirmwareInstallStatus returns the status of the firmware install process.
//
// parameters:
// installVersion (required) - the version this method should check is installed.
// component (optional) - the component slug for the component update being installed.
// taskID (optional) - the task identifier.
//
// return values:
// status - returns one of the FirmwareInstall statuses (see devices/constants.go).
FirmwareInstallStatus(ctx context.Context, installVersion, component, taskID string) (status string, err error)
}
// firmwareInstallVerifierProvider is an internal struct to correlate an implementation/provider and its name
type firmwareInstallVerifierProvider struct {
name string
FirmwareInstallVerifier
}
// firmwareInstallStatus returns the status of the firmware install process
func firmwareInstallStatus(ctx context.Context, installVersion, component, taskID string, generic []firmwareInstallVerifierProvider) (status string, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range generic {
if elem.FirmwareInstallVerifier == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return status, metadata, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
status, vErr := elem.FirmwareInstallStatus(ctx, installVersion, component, taskID)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = err.Error()
continue
}
metadata.SuccessfulProvider = elem.name
return status, metadata, nil
}
}
return status, metadata, multierror.Append(err, errors.New("failure in FirmwareInstallStatus"))
}
// FirmwareInstallStatusFromInterfaces identifies implementations of the FirmwareInstallVerifier interface and passes the found implementations to the firmwareInstallStatus() wrapper.
func FirmwareInstallStatusFromInterfaces(ctx context.Context, installVersion, component, taskID string, generic []interface{}) (status string, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]firmwareInstallVerifierProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := firmwareInstallVerifierProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FirmwareInstallVerifier:
temp.FirmwareInstallVerifier = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a FirmwareInstallVerifier implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return taskID, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no FirmwareInstallVerifier implementations found"),
),
)
}
return firmwareInstallStatus(ctx, installVersion, component, taskID, implementations)
}
// FirmwareInstallProvider defines an interface to upload and initiate a firmware install in the same implementation method
//
// Its intended to deprecate the FirmwareInstall interface
type FirmwareInstallProvider interface {
// FirmwareInstallUploadAndInitiate uploads _and_ initiates the firmware install process.
//
// return values:
// taskID - A taskID is returned if the update process on the BMC returns an identifier for the update process.
FirmwareInstallUploadAndInitiate(ctx context.Context, component string, file *os.File) (taskID string, err error)
}
// firmwareInstallProvider is an internal struct to correlate an implementation/provider and its name
type firmwareInstallProvider struct {
name string
FirmwareInstallProvider
}
// firmwareInstall uploads and initiates firmware update for the component
func firmwareInstallUploadAndInitiate(ctx context.Context, component string, file *os.File, generic []firmwareInstallProvider) (taskID string, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range generic {
if elem.FirmwareInstallProvider == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return taskID, metadata, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
taskID, vErr := elem.FirmwareInstallUploadAndInitiate(ctx, component, file)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = err.Error()
continue
}
metadata.SuccessfulProvider = elem.name
return taskID, metadata, nil
}
}
return taskID, metadata, multierror.Append(err, errors.New("failure in FirmwareInstallUploadAndInitiate"))
}
// FirmwareInstallUploadAndInitiateFromInterfaces identifies implementations of the FirmwareInstallProvider interface and passes the found implementations to the firmwareInstallUploadAndInitiate() wrapper
func FirmwareInstallUploadAndInitiateFromInterfaces(ctx context.Context, component string, file *os.File, generic []interface{}) (taskID string, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]firmwareInstallProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := firmwareInstallProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FirmwareInstallProvider:
temp.FirmwareInstallProvider = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a FirmwareInstallProvider implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return taskID, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no FirmwareInstallProvider implementations found"),
),
)
}
return firmwareInstallUploadAndInitiate(ctx, component, file, implementations)
}
// FirmwareInstallerUploaded defines an interface to install firmware that was previously uploaded with FirmwareUpload
type FirmwareInstallerUploaded interface {
// FirmwareInstallUploaded uploads firmware update payload to the BMC returning the firmware install task ID
//
// parameters:
// component - the component slug for the component update being installed.
// uploadTaskID - the taskID for the firmware upload verify task (returned by FirmwareUpload)
//
// return values:
// installTaskID - A installTaskID is returned if the update process on the BMC returns an identifier for the firmware install process.
FirmwareInstallUploaded(ctx context.Context, component, uploadTaskID string) (taskID string, err error)
}
// firmwareInstallerProvider is an internal struct to correlate an implementation/provider and its name
type firmwareInstallerWithOptionsProvider struct {
name string
FirmwareInstallerUploaded
}
// firmwareInstallUploaded uploads and initiates firmware update for the component
func firmwareInstallUploaded(ctx context.Context, component, uploadTaskID string, generic []firmwareInstallerWithOptionsProvider) (installTaskID string, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range generic {
if elem.FirmwareInstallerUploaded == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return installTaskID, metadata, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
var vErr error
installTaskID, vErr = elem.FirmwareInstallUploaded(ctx, component, uploadTaskID)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = err.Error()
continue
}
metadata.SuccessfulProvider = elem.name
return installTaskID, metadata, nil
}
}
return installTaskID, metadata, multierror.Append(err, errors.New("failure in FirmwareInstallUploaded"))
}
// FirmwareInstallerUploadedFromInterfaces identifies implementations of the FirmwareInstallUploaded interface and passes the found implementations to the firmwareInstallUploaded() wrapper
func FirmwareInstallerUploadedFromInterfaces(ctx context.Context, component, uploadTaskID string, generic []interface{}) (installTaskID string, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]firmwareInstallerWithOptionsProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := firmwareInstallerWithOptionsProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FirmwareInstallerUploaded:
temp.FirmwareInstallerUploaded = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a FirmwareInstallerUploaded implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return installTaskID, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no FirmwareInstallerUploaded implementations found"),
),
)
}
return firmwareInstallUploaded(ctx, component, uploadTaskID, implementations)
}
type FirmwareInstallStepsGetter interface {
FirmwareInstallSteps(ctx context.Context, component string) ([]constants.FirmwareInstallStep, error)
}
// firmwareInstallStepsGetterProvider is an internal struct to correlate an implementation/provider and its name
type firmwareInstallStepsGetterProvider struct {
name string
FirmwareInstallStepsGetter
}
// FirmwareInstallStepsFromInterfaces identifies implementations of the FirmwareInstallStepsGetter interface and passes the found implementations to the firmwareInstallSteps() wrapper.
func FirmwareInstallStepsFromInterfaces(ctx context.Context, component string, generic []interface{}) (steps []constants.FirmwareInstallStep, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]firmwareInstallStepsGetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := firmwareInstallStepsGetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FirmwareInstallStepsGetter:
temp.FirmwareInstallStepsGetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a FirmwareInstallStepsGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return steps, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no FirmwareInstallStepsGetter implementations found"),
),
)
}
return firmwareInstallSteps(ctx, component, implementations)
}
func firmwareInstallSteps(ctx context.Context, component string, generic []firmwareInstallStepsGetterProvider) (steps []constants.FirmwareInstallStep, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range generic {
if elem.FirmwareInstallStepsGetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return steps, metadata, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
steps, vErr := elem.FirmwareInstallSteps(ctx, component)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = err.Error()
continue
}
metadata.SuccessfulProvider = elem.name
return steps, metadata, nil
}
}
return steps, metadata, multierror.Append(err, errors.New("failure in FirmwareInstallSteps"))
}
type FirmwareUploader interface {
FirmwareUpload(ctx context.Context, component string, file *os.File) (uploadVerifyTaskID string, err error)
}
// firmwareUploaderProvider is an internal struct to correlate an implementation/provider and its name
type firmwareUploaderProvider struct {
name string
FirmwareUploader
}
// FirmwareUploaderFromInterfaces identifies implementations of the FirmwareUploader interface and passes the found implementations to the firmwareUpload() wrapper.
func FirmwareUploadFromInterfaces(ctx context.Context, component string, file *os.File, generic []interface{}) (taskID string, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]firmwareUploaderProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := firmwareUploaderProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FirmwareUploader:
temp.FirmwareUploader = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a FirmwareUploader implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return taskID, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no FirmwareUploader implementations found"),
),
)
}
return firmwareUpload(ctx, component, file, implementations)
}
func firmwareUpload(ctx context.Context, component string, file *os.File, generic []firmwareUploaderProvider) (taskID string, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range generic {
if elem.FirmwareUploader == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return taskID, metadata, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
taskID, vErr := elem.FirmwareUpload(ctx, component, file)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = err.Error()
continue
}
metadata.SuccessfulProvider = elem.name
return taskID, metadata, nil
}
}
return taskID, metadata, multierror.Append(err, errors.New("failure in FirmwareUpload"))
}
// FirmwareTaskVerifier defines an interface to check the status for firmware related tasks queued on the BMC.
// these could be a an firmware upload and verify task or a firmware install task.
//
// This is to replace the FirmwareInstallVerifier interface
type FirmwareTaskVerifier interface {
// FirmwareTaskStatus returns the status of the firmware upload process.
//
// parameters:
// kind (required) - The FirmwareInstallStep
// component (optional) - the component slug for the component that the firmware was uploaded for.
// taskID (required) - the task identifier.
// installVersion (optional) - the firmware version being installed as part of the task if applicable.
//
// return values:
// state - returns one of the FirmwareTask statuses (see devices/constants.go).
// status - returns firmware task progress or other arbitrary task information.
FirmwareTaskStatus(ctx context.Context, kind bconsts.FirmwareInstallStep, component, taskID, installVersion string) (state constants.TaskState, status string, err error)
}
// firmwareTaskVerifierProvider is an internal struct to correlate an implementation/provider and its name
type firmwareTaskVerifierProvider struct {
name string
FirmwareTaskVerifier
}
// firmwareTaskStatus returns the status of the firmware upload process.
func firmwareTaskStatus(ctx context.Context, kind bconsts.FirmwareInstallStep, component, taskID, installVersion string, generic []firmwareTaskVerifierProvider) (state constants.TaskState, status string, metadata Metadata, err error) {
metadata = newMetadata()
for _, elem := range generic {
if elem.FirmwareTaskVerifier == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return state, status, metadata, err
default:
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, elem.name)
state, status, vErr := elem.FirmwareTaskStatus(ctx, kind, component, taskID, installVersion)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
metadata.FailedProviderDetail[elem.name] = err.Error()
continue
}
metadata.SuccessfulProvider = elem.name
return state, status, metadata, nil
}
}
return state, status, metadata, multierror.Append(err, errors.New("failure in FirmwareTaskStatus"))
}
// FirmwareTaskStatusFromInterfaces identifies implementations of the FirmwareTaskVerifier interface and passes the found implementations to the firmwareTaskStatus() wrapper.
func FirmwareTaskStatusFromInterfaces(ctx context.Context, kind bconsts.FirmwareInstallStep, component, taskID, installVersion string, generic []interface{}) (state constants.TaskState, status string, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]firmwareTaskVerifierProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := firmwareTaskVerifierProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FirmwareTaskVerifier:
temp.FirmwareTaskVerifier = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a FirmwareTaskVerifier implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return state, status, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no FirmwareTaskVerifier implementations found"),
),
)
}
return firmwareTaskStatus(ctx, kind, component, taskID, installVersion, implementations)
}
================================================
FILE: bmc/firmware_test.go
================================================
package bmc
import (
"context"
"io"
"os"
"testing"
"time"
"github.com/bmc-toolbox/bmclib/v2/constants"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/bmc-toolbox/common"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
type firmwareInstallTester struct {
returnTaskID string
returnError error
}
func (f *firmwareInstallTester) FirmwareInstall(ctx context.Context, component, applyAt string, forceInstall bool, reader io.Reader) (taskID string, err error) {
return f.returnTaskID, f.returnError
}
func (r *firmwareInstallTester) Name() string {
return "foo"
}
func TestFirmwareInstall(t *testing.T) {
testCases := []struct {
testName string
component string
applyAt string
forceInstall bool
reader io.Reader
returnTaskID string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", common.SlugBIOS, string(constants.OnReset), false, nil, "1234", nil, 5 * time.Second, "foo", 1},
{"failure with metadata", common.SlugBIOS, string(constants.OnReset), false, nil, "1234", bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", common.SlugBIOS, string(constants.OnReset), false, nil, "1234", context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := firmwareInstallTester{returnTaskID: tc.returnTaskID, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
taskID, metadata, err := firmwareInstall(ctx, tc.component, tc.applyAt, tc.forceInstall, tc.reader, []firmwareInstallerProvider{{tc.providerName, &testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnTaskID, taskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
func TestFirmwareInstallFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
component string
applyAt string
forceInstall bool
reader io.Reader
returnTaskID string
returnError error
providerName string
badImplementation bool
}{
{"success with metadata", common.SlugBIOS, string(constants.OnReset), false, nil, "1234", nil, "foo", false},
{"failure with metadata", common.SlugBIOS, string(constants.OnReset), false, nil, "1234", bmclibErrs.ErrProviderImplementation, "foo", true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := &firmwareInstallTester{returnTaskID: tc.returnTaskID, returnError: tc.returnError}
generic = []interface{}{testImplementation}
}
taskID, metadata, err := FirmwareInstallFromInterfaces(context.Background(), tc.component, tc.applyAt, tc.forceInstall, tc.reader, generic)
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnTaskID, taskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
type firmwareInstallStatusTester struct {
returnStatus string
returnError error
}
func (f *firmwareInstallStatusTester) FirmwareInstallStatus(ctx context.Context, installVersion, component, taskID string) (status string, err error) {
return f.returnStatus, f.returnError
}
func (r *firmwareInstallStatusTester) Name() string {
return "foo"
}
func TestFirmwareInstallStatus(t *testing.T) {
testCases := []struct {
testName string
component string
installVersion string
taskID string
returnStatus string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", common.SlugBIOS, "1.1", "1234", constants.FirmwareInstallComplete, nil, 5 * time.Second, "foo", 1},
{"failure with metadata", common.SlugBIOS, "1.1", "1234", constants.FirmwareInstallFailed, bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", common.SlugBIOS, "1.1", "1234", "", context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := firmwareInstallStatusTester{returnStatus: tc.returnStatus, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 4
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
taskID, metadata, err := firmwareInstallStatus(ctx, tc.installVersion, tc.component, tc.taskID, []firmwareInstallVerifierProvider{{tc.providerName, &testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnStatus, taskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
func TestFirmwareInstallStatusFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
component string
installVersion string
taskID string
returnStatus string
returnError error
providerName string
badImplementation bool
}{
{"success with metadata", common.SlugBIOS, "1.1", "1234", "status-done", nil, "foo", false},
{"failure with bad implementation", common.SlugBIOS, "1.1", "1234", "status-done", bmclibErrs.ErrProviderImplementation, "foo", true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := &firmwareInstallStatusTester{returnStatus: tc.returnStatus, returnError: tc.returnError}
generic = []interface{}{testImplementation}
}
status, metadata, err := FirmwareInstallStatusFromInterfaces(context.Background(), tc.component, tc.installVersion, tc.taskID, generic)
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnStatus, status)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
type firmwareInstallUploadAndInitiateTester struct {
returnTaskID string
returnError error
}
func (f *firmwareInstallUploadAndInitiateTester) FirmwareInstallUploadAndInitiate(ctx context.Context, component string, file *os.File) (taskID string, err error) {
return f.returnTaskID, f.returnError
}
func (r *firmwareInstallUploadAndInitiateTester) Name() string {
return "foo"
}
func TestFirmwareInstallUploadAndInitiate(t *testing.T) {
testCases := []struct {
testName string
component string
file *os.File
returnTaskID string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", "componentA", &os.File{}, "1234", nil, 5 * time.Second, "foo", 1},
{"failure with metadata", "componentB", &os.File{}, "1234", errors.New("failed to upload and initiate"), 5 * time.Second, "foo", 1},
{"failure with context timeout", "componentC", &os.File{}, "", context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := &firmwareInstallUploadAndInitiateTester{returnTaskID: tc.returnTaskID, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
taskID, metadata, err := firmwareInstallUploadAndInitiate(ctx, tc.component, tc.file, []firmwareInstallProvider{{tc.providerName, testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnTaskID, taskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
func TestFirmwareInstallUploadAndInitiateFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
component string
file *os.File
returnTaskID string
returnError error
providerName string
badImplementation bool
}{
{"success with metadata", "componentA", &os.File{}, "1234", nil, "foo", false},
{"failure with bad implementation", "componentB", &os.File{}, "1234", bmclibErrs.ErrProviderImplementation, "foo", true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := &firmwareInstallUploadAndInitiateTester{returnTaskID: tc.returnTaskID, returnError: tc.returnError}
generic = []interface{}{testImplementation}
}
taskID, metadata, err := FirmwareInstallUploadAndInitiateFromInterfaces(context.Background(), tc.component, tc.file, generic)
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnTaskID, taskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
type firmwareInstallUploadTester struct {
TaskID string
Err error
}
func (f *firmwareInstallUploadTester) FirmwareInstallUploaded(ctx context.Context, component, uploadTaskID string) (taskID string, err error) {
return f.TaskID, f.Err
}
func (r *firmwareInstallUploadTester) Name() string {
return "foo"
}
func TestFirmwareInstallUploaded(t *testing.T) {
testCases := []struct {
testName string
component string
uploadTaskID string
returnTaskID string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", common.SlugBIOS, "1234", "5678", nil, 5 * time.Second, "foo", 1},
{"failure with metadata", common.SlugBIOS, "1234", "", bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", common.SlugBIOS, "1234", "", context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
mockImplementation := &firmwareInstallUploadTester{TaskID: tc.returnTaskID, Err: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 4
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
taskID, metadata, err := firmwareInstallUploaded(ctx, tc.component, tc.uploadTaskID, []firmwareInstallerWithOptionsProvider{{tc.providerName, mockImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnTaskID, taskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
func TestFirmwareInstallerUploadedFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
component string
uploadTaskID string
returnTaskID string
returnError error
providerName string
badImplementation bool
}{
{"success with metadata", common.SlugBIOS, "1234", "5678", nil, "foo", false},
{"failure with bad implementation", common.SlugBIOS, "1234", "", bmclibErrs.ErrProviderImplementation, "foo", true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
mockImplementation := &firmwareInstallUploadTester{TaskID: tc.returnTaskID, Err: tc.returnError}
generic = []interface{}{mockImplementation}
}
installTaskID, metadata, err := FirmwareInstallerUploadedFromInterfaces(context.Background(), tc.component, tc.uploadTaskID, generic)
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnTaskID, installTaskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
type firmwareUploadTester struct {
returnTaskID string
returnError error
}
func (f *firmwareUploadTester) FirmwareUpload(ctx context.Context, component string, file *os.File) (uploadVerifyTaskID string, err error) {
return f.returnTaskID, f.returnError
}
func (r *firmwareUploadTester) Name() string {
return "foo"
}
func TestFirmwareUpload(t *testing.T) {
testCases := []struct {
testName string
component string
file *os.File
returnTaskID string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", common.SlugBIOS, nil, "1234", nil, 5 * time.Second, "foo", 1},
{"failure with metadata", common.SlugBIOS, nil, "1234", bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", common.SlugBIOS, nil, "1234", context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := firmwareUploadTester{returnTaskID: tc.returnTaskID, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
taskID, metadata, err := firmwareUpload(ctx, tc.component, tc.file, []firmwareUploaderProvider{{tc.providerName, &testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnTaskID, taskID)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
type firmwareInstallStepsGetterTester struct {
Steps []constants.FirmwareInstallStep
Err error
}
func (m *firmwareInstallStepsGetterTester) FirmwareInstallSteps(ctx context.Context, component string) ([]constants.FirmwareInstallStep, error) {
return m.Steps, m.Err
}
func (m *firmwareInstallStepsGetterTester) Name() string {
return "foo"
}
func TestFirmwareInstallStepsFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
component string
returnSteps []constants.FirmwareInstallStep
returnError error
providerName string
badImplementation bool
}{
{"success with metadata", common.SlugBIOS, []constants.FirmwareInstallStep{constants.FirmwareInstallStepUpload, constants.FirmwareInstallStepInstallStatus}, nil, "foo", false},
{"failure with bad implementation", common.SlugBIOS, nil, bmclibErrs.ErrProviderImplementation, "foo", true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
mockImplementation := &firmwareInstallStepsGetterTester{Steps: tc.returnSteps, Err: tc.returnError}
generic = []interface{}{mockImplementation}
}
steps, metadata, err := FirmwareInstallStepsFromInterfaces(context.Background(), tc.component, generic)
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnSteps, steps)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
type firmwareInstallStepsTester struct {
returnSteps []constants.FirmwareInstallStep
returnError error
}
func (f *firmwareInstallStepsTester) FirmwareInstallSteps(ctx context.Context, component string) (steps []constants.FirmwareInstallStep, err error) {
return f.returnSteps, f.returnError
}
func (r *firmwareInstallStepsTester) Name() string {
return "foo"
}
func TestFirmwareInstallSteps(t *testing.T) {
testCases := []struct {
testName string
component string
returnSteps []constants.FirmwareInstallStep
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", common.SlugBIOS, []constants.FirmwareInstallStep{constants.FirmwareInstallStepUpload, constants.FirmwareInstallStepInstallStatus}, nil, 5 * time.Second, "foo", 1},
{"failure with metadata", common.SlugBIOS, nil, bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", common.SlugBIOS, nil, context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := firmwareInstallStepsTester{returnSteps: tc.returnSteps, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
steps, metadata, err := firmwareInstallSteps(ctx, tc.component, []firmwareInstallStepsGetterProvider{{tc.providerName, &testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnSteps, steps)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
type firmwareTaskStatusTester struct {
returnState constants.TaskState
returnStatus string
returnError error
}
func (f *firmwareTaskStatusTester) FirmwareTaskStatus(ctx context.Context, kind constants.FirmwareInstallStep, component, taskID, installVersion string) (state constants.TaskState, status string, err error) {
return f.returnState, f.returnStatus, f.returnError
}
func (r *firmwareTaskStatusTester) Name() string {
return "foo"
}
func TestFirmwareTaskStatus(t *testing.T) {
testCases := []struct {
testName string
kind constants.FirmwareInstallStep
component string
taskID string
installVersion string
returnState constants.TaskState
returnStatus string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", constants.FirmwareInstallStepUpload, common.SlugBIOS, "1234", "1.0", constants.FirmwareInstallComplete, "Upload completed", nil, 5 * time.Second, "foo", 1},
{"failure with metadata", constants.FirmwareInstallStepUpload, common.SlugBIOS, "1234", "1.0", constants.FirmwareInstallFailed, "Upload failed", bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", constants.FirmwareInstallStepUpload, common.SlugBIOS, "1234", "1.0", "", "", context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := firmwareTaskStatusTester{returnState: tc.returnState, returnStatus: tc.returnStatus, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
state, status, metadata, err := firmwareTaskStatus(ctx, tc.kind, tc.component, tc.taskID, tc.installVersion, []firmwareTaskVerifierProvider{{tc.providerName, &testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnState, state)
assert.Equal(t, tc.returnStatus, status)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
func TestFirmwareTaskStatusFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
kind constants.FirmwareInstallStep
component string
taskID string
installVersion string
returnState constants.TaskState
returnStatus string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", constants.FirmwareInstallStepUpload, common.SlugBIOS, "1234", "1.0", constants.Complete, "uploading", nil, 5 * time.Second, "foo", 1},
{"failure with metadata", constants.FirmwareInstallStepUpload, common.SlugBIOS, "1234", "1.0", constants.Failed, "failed", bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", constants.FirmwareInstallStepUpload, common.SlugBIOS, "1234", "1.0", "", "", context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := firmwareTaskStatusTester{
returnState: tc.returnState,
returnStatus: tc.returnStatus,
returnError: tc.returnError,
}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
state, status, metadata, err := FirmwareTaskStatusFromInterfaces(ctx, tc.kind, tc.component, tc.taskID, tc.installVersion, []interface{}{&testImplementation})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnState, state)
assert.Equal(t, tc.returnStatus, status)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
================================================
FILE: bmc/floppy.go
================================================
package bmc
import (
"context"
"fmt"
"io"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// FloppyImageMounter defines methods to upload a floppy image
type FloppyImageMounter interface {
MountFloppyImage(ctx context.Context, image io.Reader) (err error)
}
// floppyImageUploaderProvider is an internal struct to correlate an implementation/provider and its name
type floppyImageUploaderProvider struct {
name string
impl FloppyImageMounter
}
// mountFloppyImage is a wrapper method to invoke methods for the FloppyImageMounter interface
func mountFloppyImage(ctx context.Context, image io.Reader, p []floppyImageUploaderProvider) (metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range p {
if elem.impl == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
uploadErr := elem.impl.MountFloppyImage(ctx, image)
if uploadErr != nil {
err = multierror.Append(err, errors.WithMessagef(uploadErr, "provider: %v", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return metadataLocal, nil
}
}
return metadataLocal, multierror.Append(err, errors.New("failed to mount floppy image"))
}
// MountFloppyImageFromInterfaces identifies implementations of the FloppyImageMounter interface and passes the found implementations to the mountFloppyImage() wrapper
func MountFloppyImageFromInterfaces(ctx context.Context, image io.Reader, p []interface{}) (metadata Metadata, err error) {
providers := make([]floppyImageUploaderProvider, 0)
for _, elem := range p {
if elem == nil {
continue
}
temp := floppyImageUploaderProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FloppyImageMounter:
temp.impl = p
providers = append(providers, temp)
default:
e := fmt.Sprintf("not a FloppyImageMounter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(providers) == 0 {
return metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
"no FloppyImageMounter implementations found",
),
)
}
return mountFloppyImage(ctx, image, providers)
}
// FloppyImageMounter defines methods to unmount a floppy image
type FloppyImageUnmounter interface {
UnmountFloppyImage(ctx context.Context) (err error)
}
// floppyImageUnmounterProvider is an internal struct to correlate an implementation/provider and its name
type floppyImageUnmounterProvider struct {
name string
impl FloppyImageUnmounter
}
// unmountFloppyImage is a wrapper method to invoke methods for the FloppyImageUnmounter interface
func unmountFloppyImage(ctx context.Context, p []floppyImageUnmounterProvider) (metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range p {
if elem.impl == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
uploadErr := elem.impl.UnmountFloppyImage(ctx)
if uploadErr != nil {
err = multierror.Append(err, errors.WithMessagef(uploadErr, "provider: %v", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return metadataLocal, nil
}
}
return metadataLocal, multierror.Append(err, errors.New("failed to unmount floppy image"))
}
// MountFloppyImageFromInterfaces identifies implementations of the FloppyImageUnmounter interface and passes the found implementations to the unmountFloppyImage() wrapper
func UnmountFloppyImageFromInterfaces(ctx context.Context, p []interface{}) (metadata Metadata, err error) {
providers := make([]floppyImageUnmounterProvider, 0)
for _, elem := range p {
if elem == nil {
continue
}
temp := floppyImageUnmounterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case FloppyImageUnmounter:
temp.impl = p
providers = append(providers, temp)
default:
e := fmt.Sprintf("not a FloppyImageUnmounter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(providers) == 0 {
return metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
"no FloppyImageUnmounter implementations found",
),
)
}
return unmountFloppyImage(ctx, providers)
}
================================================
FILE: bmc/floppy_test.go
================================================
package bmc
import (
"context"
"io"
"testing"
"time"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/stretchr/testify/assert"
)
type mountFloppyImageTester struct {
returnError error
}
func (p *mountFloppyImageTester) MountFloppyImage(ctx context.Context, reader io.Reader) (err error) {
return p.returnError
}
func (p *mountFloppyImageTester) Name() string {
return "foo"
}
func TestMountFloppyFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
image io.Reader
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
badImplementation bool
}{
{"success with metadata", nil, nil, 5 * time.Second, "foo", 1, false},
{"failure with bad implementation", nil, bmclibErrs.ErrProviderImplementation, 1 * time.Nanosecond, "foo", 1, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := &mountFloppyImageTester{returnError: tc.returnError}
generic = []interface{}{testImplementation}
}
metadata, err := MountFloppyImageFromInterfaces(context.Background(), tc.image, generic)
if tc.returnError != nil {
assert.ErrorContains(t, err, tc.returnError.Error())
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnError, err)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
type unmountFloppyImageTester struct {
returnError error
}
func (p *unmountFloppyImageTester) UnmountFloppyImage(ctx context.Context) (err error) {
return p.returnError
}
func (p *unmountFloppyImageTester) Name() string {
return "foo"
}
func TestUnmountFloppyFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
badImplementation bool
}{
{"success with metadata", nil, 5 * time.Second, "foo", 1, false},
{"failure with bad implementation", bmclibErrs.ErrProviderImplementation, 1 * time.Nanosecond, "foo", 1, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := &unmountFloppyImageTester{returnError: tc.returnError}
generic = []interface{}{testImplementation}
}
metadata, err := UnmountFloppyImageFromInterfaces(context.Background(), generic)
if tc.returnError != nil {
assert.ErrorContains(t, err, tc.returnError.Error())
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnError, err)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
================================================
FILE: bmc/inventory.go
================================================
package bmc
import (
"context"
"fmt"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/bmc-toolbox/common"
)
// InventoryGetter defines methods to retrieve device hardware and firmware inventory
type InventoryGetter interface {
Inventory(ctx context.Context) (device *common.Device, err error)
}
type inventoryGetterProvider struct {
name string
InventoryGetter
}
// inventory returns hardware and firmware inventory
func inventory(ctx context.Context, generic []inventoryGetterProvider) (device *common.Device, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range generic {
if elem.InventoryGetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return device, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
device, vErr := elem.Inventory(ctx)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue
}
metadataLocal.SuccessfulProvider = elem.name
return device, metadataLocal, nil
}
}
return device, metadataLocal, multierror.Append(err, errors.New("failure to get device inventory"))
}
// GetInventoryFromInterfaces identifies implementations of the InventoryGetter interface and passes the found implementations to the inventory() wrapper method
func GetInventoryFromInterfaces(ctx context.Context, generic []interface{}) (device *common.Device, metadata Metadata, err error) {
metadata = newMetadata()
implementations := make([]inventoryGetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := inventoryGetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case InventoryGetter:
temp.InventoryGetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a InventoryGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return device, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no InventoryGetter implementations found"),
),
)
}
return inventory(ctx, implementations)
}
================================================
FILE: bmc/inventory_test.go
================================================
package bmc
import (
"context"
"testing"
"time"
"github.com/bmc-toolbox/bmclib/v2/errors"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/bmc-toolbox/common"
"github.com/stretchr/testify/assert"
)
type inventoryGetterTester struct {
returnDevice *common.Device
returnError error
}
func (f *inventoryGetterTester) Inventory(ctx context.Context) (device *common.Device, err error) {
return f.returnDevice, f.returnError
}
func (f *inventoryGetterTester) Name() string {
return "foo"
}
func TestInventory(t *testing.T) {
testCases := []struct {
testName string
returnDevice *common.Device
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", &common.Device{Common: common.Common{Vendor: "foo"}}, nil, 5 * time.Second, "foo", 1},
{"failure with metadata", nil, errors.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", nil, context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := inventoryGetterTester{returnDevice: tc.returnDevice, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
device, metadata, err := inventory(ctx, []inventoryGetterProvider{{tc.providerName, &testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnDevice, device)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
func TestInventoryFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
returnDevice *common.Device
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
badImplementation bool
}{
{"success with metadata", &common.Device{Common: common.Common{Vendor: "foo"}}, nil, 5 * time.Second, "foo", 1, false},
{"failure with bad implementation", nil, bmclibErrs.ErrProviderImplementation, 5 * time.Second, "foo", 1, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := &inventoryGetterTester{returnDevice: tc.returnDevice, returnError: tc.returnError}
generic = []interface{}{testImplementation}
}
device, metadata, err := GetInventoryFromInterfaces(context.Background(), generic)
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnDevice, device)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
================================================
FILE: bmc/nmi.go
================================================
package bmc
import (
"context"
"errors"
"fmt"
"time"
"github.com/hashicorp/go-multierror"
)
type NMISender interface {
SendNMI(ctx context.Context) error
}
func sendNMI(ctx context.Context, timeout time.Duration, sender NMISender, metadata *Metadata) error {
senderName := getProviderName(sender)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
metadata.ProvidersAttempted = append(metadata.ProvidersAttempted, senderName)
err := sender.SendNMI(ctx)
if err != nil {
metadata.FailedProviderDetail[senderName] = err.Error()
return err
}
metadata.SuccessfulProvider = senderName
return nil
}
// SendNMIFromInterface will look for providers that implement NMISender
// and attempt to call SendNMI until a provider is successful,
// or all providers have been exhausted.
func SendNMIFromInterface(
ctx context.Context,
timeout time.Duration,
providers []interface{},
) (metadata Metadata, err error) {
metadata = newMetadata()
for _, provider := range providers {
sender, ok := provider.(NMISender)
if !ok {
err = multierror.Append(err, fmt.Errorf("not an NMISender implementation: %T", provider))
continue
}
sendNMIErr := sendNMI(ctx, timeout, sender, &metadata)
if sendNMIErr != nil {
err = multierror.Append(err, sendNMIErr)
continue
}
return metadata, nil
}
if len(metadata.ProvidersAttempted) == 0 {
err = multierror.Append(err, errors.New("no NMISender implementations found"))
} else {
err = multierror.Append(err, errors.New("failed to send NMI"))
}
return metadata, err
}
================================================
FILE: bmc/nmi_test.go
================================================
package bmc
import (
"context"
"testing"
"time"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
type mockNMISender struct {
err error
}
func (m *mockNMISender) SendNMI(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
return m.err
}
}
func (m *mockNMISender) Name() string {
return "mock"
}
func TestSendNMIFromInterface(t *testing.T) {
testCases := []struct {
name string
mockSenders []interface{}
errMsg string
isTimedout bool
expectedMetadata Metadata
}{
{
name: "success",
mockSenders: []interface{}{&mockNMISender{}},
expectedMetadata: Metadata{
SuccessfulProvider: "mock",
ProvidersAttempted: []string{"mock"},
FailedProviderDetail: make(map[string]string),
},
},
{
name: "success with multiple senders",
mockSenders: []interface{}{
nil,
"foo",
&mockNMISender{err: errors.New("err from sender")},
&mockNMISender{},
},
expectedMetadata: Metadata{
SuccessfulProvider: "mock",
ProvidersAttempted: []string{"mock", "mock"},
FailedProviderDetail: map[string]string{"mock": "err from sender"},
},
},
{
name: "not an nmisender",
mockSenders: []interface{}{nil},
errMsg: "not an NMISender",
expectedMetadata: Metadata{
FailedProviderDetail: make(map[string]string),
},
},
{
name: "no nmisenders",
mockSenders: []interface{}{},
errMsg: "no NMISender implementations found",
expectedMetadata: Metadata{
FailedProviderDetail: make(map[string]string),
},
},
{
name: "timed out",
mockSenders: []interface{}{&mockNMISender{}},
isTimedout: true,
errMsg: "context deadline exceeded",
expectedMetadata: Metadata{
ProvidersAttempted: []string{"mock"},
FailedProviderDetail: map[string]string{"mock": "context deadline exceeded"},
},
},
{
name: "error from nmisender",
mockSenders: []interface{}{&mockNMISender{err: errors.New("foobar")}},
errMsg: "foobar",
expectedMetadata: Metadata{
ProvidersAttempted: []string{"mock"},
FailedProviderDetail: map[string]string{"mock": "foobar"},
},
},
{
name: "error when fail to send",
mockSenders: []interface{}{&mockNMISender{err: errors.New("err from sender")}},
errMsg: "failed to send NMI",
expectedMetadata: Metadata{
ProvidersAttempted: []string{"mock"},
FailedProviderDetail: map[string]string{"mock": "err from sender"},
},
},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
timeout := time.Second * 60
if tt.isTimedout {
timeout = 0
}
metadata, err := SendNMIFromInterface(context.Background(), timeout, tt.mockSenders)
if tt.errMsg == "" {
assert.NoError(t, err)
} else {
assert.ErrorContains(t, err, tt.errMsg)
}
assert.Equal(t, tt.expectedMetadata, metadata)
})
}
}
================================================
FILE: bmc/postcode.go
================================================
package bmc
import (
"context"
"fmt"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// PostCodeGetter defines methods to retrieve device BIOS/UEFI POST code
type PostCodeGetter interface {
// PostCode retrieves the BIOS/UEFI POST code from a device
//
// returns 'status' which is a (bmclib specific) string identifier for the POST code
// and 'code' with the actual POST code returned to bmclib by the device
PostCode(ctx context.Context) (status string, code int, err error)
}
type postCodeGetterProvider struct {
name string
PostCodeGetter
}
// postCode returns the device BIOS/UEFI POST code
func postCode(ctx context.Context, generic []postCodeGetterProvider) (status string, code int, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range generic {
if elem.PostCodeGetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return status, code, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
status, code, vErr := elem.PostCode(ctx)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
err = multierror.Append(err, vErr)
continue
}
metadataLocal.SuccessfulProvider = elem.name
return status, code, metadataLocal, nil
}
}
return status, code, metadataLocal, multierror.Append(err, errors.New("failure to get device POST code"))
}
// GetPostCodeFromInterfaces identifies implementations of the PostCodeGetter interface and passes the found implementations to the postCode() wrapper method.
func GetPostCodeInterfaces(ctx context.Context, generic []interface{}) (status string, code int, metadata Metadata, err error) {
implementations := make([]postCodeGetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := postCodeGetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case PostCodeGetter:
temp.PostCodeGetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a PostCodeGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return status, code, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no PostCodeGetter implementations found"),
),
)
}
return postCode(ctx, implementations)
}
================================================
FILE: bmc/postcode_test.go
================================================
package bmc
import (
"context"
"testing"
"time"
"github.com/bmc-toolbox/bmclib/v2/constants"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/stretchr/testify/assert"
)
type postCodeGetterTester struct {
returnStatus string
returnCode int
returnError error
}
func (p *postCodeGetterTester) PostCode(ctx context.Context) (status string, code int, err error) {
return p.returnStatus, p.returnCode, p.returnError
}
func (p *postCodeGetterTester) Name() string {
return "foo"
}
func TestPostCode(t *testing.T) {
testCases := []struct {
testName string
returnStatus string
returnCode int
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
}{
{"success with metadata", constants.POSTStateOS, 164, nil, 5 * time.Second, "foo", 1},
{"failure with metadata", constants.POSTCodeUnknown, 0, bmclibErrs.ErrNon200Response, 5 * time.Second, "foo", 1},
{"failure with context timeout", "", 0, context.DeadlineExceeded, 1 * time.Nanosecond, "foo", 1},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
testImplementation := postCodeGetterTester{returnStatus: tc.returnStatus, returnCode: tc.returnCode, returnError: tc.returnError}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
status, code, metadata, err := postCode(ctx, []postCodeGetterProvider{{tc.providerName, &testImplementation}})
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnStatus, status)
assert.Equal(t, tc.returnCode, code)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
assert.Equal(t, tc.providersAttempted, len(metadata.ProvidersAttempted))
})
}
}
func TestPostCodeFromInterfaces(t *testing.T) {
testCases := []struct {
testName string
returnStatus string
returnCode int
returnError error
ctxTimeout time.Duration
providerName string
providersAttempted int
badImplementation bool
}{
{"success with metadata", constants.POSTStateOS, 164, nil, 5 * time.Second, "foo", 1, false},
{"failure with bad implementation", "", 0, bmclibErrs.ErrProviderImplementation, 1 * time.Nanosecond, "foo", 1, true},
}
for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := &postCodeGetterTester{returnStatus: tc.returnStatus, returnCode: tc.returnCode, returnError: tc.returnError}
generic = []interface{}{testImplementation}
}
status, code, metadata, err := GetPostCodeInterfaces(context.Background(), generic)
if tc.returnError != nil {
assert.ErrorIs(t, err, tc.returnError)
return
}
if err != nil {
t.Fatal(err)
}
assert.Equal(t, tc.returnStatus, status)
assert.Equal(t, tc.returnCode, code)
assert.Equal(t, tc.providerName, metadata.SuccessfulProvider)
})
}
}
================================================
FILE: bmc/power.go
================================================
package bmc
import (
"context"
"fmt"
"time"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// PowerSetter sets the power state of a BMC
type PowerSetter interface {
// PowerSet sets the power state of a Machine through a BMC.
// While the state's accepted are ultimately up to what the implementation
// expects, implementations should generally try to provide support for the following
// states, modeled after the functionality available in `ipmitool chassis power`.
//
// "on": Power up chassis. should not error if the machine is already on
// "off": Hard powers down chassis. should not error if the machine is already off
// "soft": Initiate a soft-shutdown of OS via ACPI.
// "reset": soft down and then power on. simulates a reboot from the host OS.
// "cycle": hard power down followed by a power on. simulates pressing a power button
// to turn the machine off then pressing the button again to turn it on.
PowerSet(ctx context.Context, state string) (ok bool, err error)
}
// PowerStateGetter gets the power state of a BMC
type PowerStateGetter interface {
PowerStateGet(ctx context.Context) (state string, err error)
}
// powerProviders is an internal struct to correlate an implementation/provider and its name
type powerProviders struct {
name string
powerStateGetter PowerStateGetter
powerSetter PowerSetter
}
// setPowerState sets the power state for a BMC, trying all interface implementations passed in
func setPowerState(ctx context.Context, timeout time.Duration, state string, p []powerProviders) (ok bool, m Metadata, err error) {
metadataLocal := Metadata{
FailedProviderDetail: make(map[string]string),
}
for _, elem := range p {
if elem.powerSetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return false, metadataLocal, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
ok, setErr := elem.powerSetter.PowerSet(ctx, state)
if setErr != nil {
err = multierror.Append(err, errors.WithMessagef(setErr, "provider: %v", elem.name))
metadataLocal.FailedProviderDetail[elem.name] = setErr.Error()
continue
}
if !ok {
err = multierror.Append(err, fmt.Errorf("provider: %v, failed to set power state", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return ok, metadataLocal, nil
}
}
return ok, metadataLocal, multierror.Append(err, errors.New("failed to set power state"))
}
// SetPowerStateFromInterfaces identifies implementations of the PostStateSetter interface and passes the found implementations to the setPowerState() wrapper.
func SetPowerStateFromInterfaces(ctx context.Context, timeout time.Duration, state string, generic []interface{}) (ok bool, metadata Metadata, err error) {
metadata = newMetadata()
powerSetter := make([]powerProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := powerProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case PowerSetter:
temp.powerSetter = p
powerSetter = append(powerSetter, temp)
default:
e := fmt.Sprintf("not a PowerSetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(powerSetter) == 0 {
return ok, metadata, multierror.Append(err, errors.New("no PowerSetter implementations found"))
}
return setPowerState(ctx, timeout, state, powerSetter)
}
// getPowerState gets the power state for a BMC, trying all interface implementations passed in
func getPowerState(ctx context.Context, timeout time.Duration, p []powerProviders) (state string, m Metadata, err error) {
metadataLocal := Metadata{
FailedProviderDetail: make(map[string]string),
}
for _, elem := range p {
if elem.powerStateGetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return state, metadataLocal, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
state, stateErr := elem.powerStateGetter.PowerStateGet(ctx)
if stateErr != nil {
err = multierror.Append(err, errors.WithMessagef(stateErr, "provider: %v", elem.name))
metadataLocal.FailedProviderDetail[elem.name] = stateErr.Error()
continue
}
metadataLocal.SuccessfulProvider = elem.name
return state, metadataLocal, nil
}
}
return state, metadataLocal, multierror.Append(err, errors.New("failed to get power state"))
}
// GetPowerStateFromInterfaces identifies implementations of the PostStateGetter interface and passes the found implementations to the getPowerState() wrapper.
func GetPowerStateFromInterfaces(ctx context.Context, timeout time.Duration, generic []interface{}) (state string, metadata Metadata, err error) {
metadata = newMetadata()
powerStateGetter := make([]powerProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := powerProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case PowerStateGetter:
temp.powerStateGetter = p
powerStateGetter = append(powerStateGetter, temp)
default:
e := fmt.Sprintf("not a PowerStateGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(powerStateGetter) == 0 {
return state, metadata, multierror.Append(err, errors.New("no PowerStateGetter implementations found"))
}
return getPowerState(ctx, timeout, powerStateGetter)
}
================================================
FILE: bmc/power_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
)
type powerTester struct {
MakeNotOK bool
MakeErrorOut bool
}
func (p *powerTester) PowerSet(ctx context.Context, state string) (ok bool, err error) {
if p.MakeErrorOut {
return ok, errors.New("power set failed")
}
if p.MakeNotOK {
return false, nil
}
return true, nil
}
func (p *powerTester) PowerStateGet(ctx context.Context) (state string, err error) {
if p.MakeErrorOut {
return state, errors.New("power state get failed")
}
return "on", nil
}
func (p *powerTester) Name() string {
return "test provider"
}
func TestSetPowerState(t *testing.T) {
testCases := map[string]struct {
state string
makeErrorOut bool
makeNotOk bool
want bool
err error
ctxTimeout time.Duration
}{
"success": {state: "off", want: true},
"not ok return": {state: "off", want: false, makeNotOk: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider, failed to set power state"), errors.New("failed to set power state")}}},
"error": {state: "off", want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider: power set failed"), errors.New("failed to set power state")}}},
"error context timeout": {state: "off", want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := powerTester{MakeErrorOut: tc.makeErrorOut, MakeNotOK: tc.makeNotOk}
expectedResult := tc.want
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := setPowerState(ctx, 0, tc.state, []powerProviders{{"test provider", nil, &testImplementation}})
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestSetPowerStateFromInterfaces(t *testing.T) {
testCases := map[string]struct {
state string
err error
badImplementation bool
want bool
withMetadata bool
}{
"success": {state: "off", want: true},
"success with metadata": {state: "on", want: true, withMetadata: true},
"no implementations found": {state: "on", want: false, badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a PowerSetter implementation: *struct {}"), errors.New("no PowerSetter implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := powerTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := tc.want
result, metadata, err := SetPowerStateFromInterfaces(context.Background(), 0, tc.state, generic)
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestGetPowerState(t *testing.T) {
testCases := map[string]struct {
state string
makeFail bool
err error
ctxTimeout time.Duration
}{
"success": {state: "on", err: nil},
"failure": {state: "on", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider: power state get failed"), errors.New("failed to get power state")}}},
"fail context timeout": {state: "on", makeFail: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := powerTester{MakeErrorOut: tc.makeFail}
expectedResult := tc.state
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := getPowerState(ctx, 0, []powerProviders{{"test provider", &testImplementation, nil}})
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestGetPowerStateFromInterfaces(t *testing.T) {
testCases := map[string]struct {
state string
err error
badImplementation bool
want string
withMetadata bool
}{
"success": {state: "on", want: "on"},
"success with metadata": {state: "on", want: "on", withMetadata: true},
"no implementations found": {state: "on", want: "", badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a PowerStateGetter implementation: *struct {}"), errors.New("no PowerStateGetter implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := powerTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := tc.want
result, metadata, err := GetPowerStateFromInterfaces(context.Background(), 0, generic)
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
================================================
FILE: bmc/provider.go
================================================
package bmc
import "fmt"
// Provider interface describes details about a provider
type Provider interface {
// Name of the provider
Name() string
}
// getProviderName returns the name a provider supplies if they implement the Provider interface
// if not implemented then the concrete type is returned
func getProviderName(provider interface{}) string {
if provider == nil {
return ""
}
switch p := provider.(type) {
case Provider:
return p.Name()
}
return fmt.Sprintf("%T", provider)
}
================================================
FILE: bmc/reset.go
================================================
package bmc
import (
"context"
"fmt"
"time"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// BMCResetter for resetting a BMC.
// resetType: "warm" resets the management console without rebooting the BMC
// resetType: "cold" reboots the BMC
type BMCResetter interface {
BmcReset(ctx context.Context, resetType string) (ok bool, err error)
}
// bmcProviders is an internal struct to correlate an implementation/provider and its name
type bmcProviders struct {
name string
bmcResetter BMCResetter
}
// resetBMC tries all implementations for a success BMC reset
func resetBMC(ctx context.Context, timeout time.Duration, resetType string, b []bmcProviders) (ok bool, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range b {
if elem.bmcResetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return false, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
ok, setErr := elem.bmcResetter.BmcReset(ctx, resetType)
if setErr != nil {
err = multierror.Append(err, errors.WithMessagef(setErr, "provider: %v", elem.name))
continue
}
if !ok {
err = multierror.Append(err, fmt.Errorf("provider: %v, failed to reset BMC", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return ok, metadataLocal, nil
}
}
return ok, metadataLocal, multierror.Append(err, errors.New("failed to reset BMC"))
}
// ResetBMCFromInterfaces identifies implementations of the BMCResetter interface and passes them to the resetBMC() wrapper method.
func ResetBMCFromInterfaces(ctx context.Context, timeout time.Duration, resetType string, generic []interface{}) (ok bool, metadata Metadata, err error) {
metadata = newMetadata()
bmcSetters := make([]bmcProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := bmcProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case BMCResetter:
temp.bmcResetter = p
bmcSetters = append(bmcSetters, temp)
default:
e := fmt.Sprintf("not a BMCResetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(bmcSetters) == 0 {
return ok, metadata, multierror.Append(err, errors.New("no BMCResetter implementations found"))
}
return resetBMC(ctx, timeout, resetType, bmcSetters)
}
================================================
FILE: bmc/reset_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
)
type resetTester struct {
MakeNotOK bool
MakeErrorOut bool
}
func (r *resetTester) BmcReset(ctx context.Context, resetType string) (ok bool, err error) {
if r.MakeErrorOut {
return ok, errors.New("bmc reset failed")
}
if r.MakeNotOK {
return false, nil
}
return true, nil
}
func (r *resetTester) Name() string {
return "test provider"
}
func TestResetBMC(t *testing.T) {
testCases := map[string]struct {
resetType string
makeErrorOut bool
makeNotOk bool
want bool
err error
ctxTimeout time.Duration
}{
"success": {resetType: "cold", want: true},
"not ok return": {resetType: "warm", want: false, makeNotOk: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider, failed to reset BMC"), errors.New("failed to reset BMC")}}},
"error": {resetType: "cold", want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider: bmc reset failed"), errors.New("failed to reset BMC")}}},
"error context timeout": {resetType: "cold", want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := resetTester{MakeErrorOut: tc.makeErrorOut, MakeNotOK: tc.makeNotOk}
expectedResult := tc.want
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := resetBMC(ctx, 0, tc.resetType, []bmcProviders{{"test provider", &testImplementation}})
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestResetBMCFromInterfaces(t *testing.T) {
testCases := map[string]struct {
resetType string
err error
badImplementation bool
want bool
withName bool
}{
"success": {resetType: "cold", want: true},
"success with metadata": {resetType: "cold", want: true, withName: true},
"no implementations found": {resetType: "warm", want: false, badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a BMCResetter implementation: *struct {}"), errors.New("no BMCResetter implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := resetTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := tc.want
result, metadata, err := ResetBMCFromInterfaces(context.Background(), 0, tc.resetType, generic)
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withName {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
================================================
FILE: bmc/screenshot.go
================================================
package bmc
import (
"context"
"fmt"
bmclibErrs "github.com/bmc-toolbox/bmclib/v2/errors"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// ScreenshotGetter interface provides methods to query for a BMC screen capture.
type ScreenshotGetter interface {
Screenshot(ctx context.Context) (image []byte, fileType string, err error)
}
type screenshotGetterProvider struct {
name string
ScreenshotGetter
}
// screenshot returns an image capture of the video output.
func screenshot(ctx context.Context, generic []screenshotGetterProvider) (image []byte, fileType string, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range generic {
if elem.ScreenshotGetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return image, fileType, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
image, fileType, vErr := elem.Screenshot(ctx)
if vErr != nil {
err = multierror.Append(err, errors.WithMessagef(vErr, "provider: %v", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return image, fileType, metadataLocal, nil
}
}
return image, fileType, metadataLocal, multierror.Append(err, errors.New("failed to capture screenshot"))
}
// ScreenshotFromInterfaces identifies implementations of the ScreenshotGetter interface and passes the found implementations to the screenshot() wrapper method.
func ScreenshotFromInterfaces(ctx context.Context, generic []interface{}) (image []byte, fileType string, metadata Metadata, err error) {
implementations := make([]screenshotGetterProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := screenshotGetterProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case ScreenshotGetter:
temp.ScreenshotGetter = p
implementations = append(implementations, temp)
default:
e := fmt.Sprintf("not a ScreenshotGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(implementations) == 0 {
return image, fileType, metadata, multierror.Append(
err,
errors.Wrap(
bmclibErrs.ErrProviderImplementation,
("no ScreenshotGetter implementations found"),
),
)
}
return screenshot(ctx, implementations)
}
================================================
FILE: bmc/screenshot_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"github.com/hashicorp/go-multierror"
"gopkg.in/go-playground/assert.v1"
)
type screenshotTester struct {
MakeErrorOut bool
}
func (r *screenshotTester) Screenshot(ctx context.Context) (img []byte, fileType string, err error) {
if r.MakeErrorOut {
return nil, "", errors.New("crappy bmc is crappy")
}
return []byte(`foobar`), "png", nil
}
func (r *screenshotTester) Name() string {
return "test screenshot provider"
}
func TestScreenshot(t *testing.T) {
testCases := map[string]struct {
makeErrorOut bool
wantImage []byte
wantFileType string
wantSuccessfulProvider string
wantProvidersAttempted []string
wantErr error
ctxTimeout time.Duration
}{
"success": {false, []byte(`foobar`), "png", "test provider", []string{"test provider"}, nil, 1 * time.Second},
"error": {true, nil, "", "", []string{"test provider"}, &multierror.Error{Errors: []error{errors.New("provider: test provider: crappy bmc is crappy"), errors.New("failed to capture screenshot")}}, 1 * time.Second},
"error context timeout": {true, nil, "", "", nil, &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, 1 * time.Nanosecond},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := screenshotTester{MakeErrorOut: tc.makeErrorOut}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
image, fileType, metadata, err := screenshot(ctx, []screenshotGetterProvider{{"test provider", &testImplementation}})
if err != nil {
if tc.wantErr == nil {
t.Fatal(err)
}
assert.Equal(t, tc.wantErr.Error(), err.Error())
} else {
assert.Equal(t, tc.wantImage, image)
assert.Equal(t, tc.wantFileType, fileType)
}
assert.Equal(t, tc.wantProvidersAttempted, metadata.ProvidersAttempted)
assert.Equal(t, tc.wantSuccessfulProvider, metadata.SuccessfulProvider)
})
}
}
func TestScreenshotFromInterfaces(t *testing.T) {
testCases := map[string]struct {
wantImage []byte
wantFileType string
wantSuccessfulProvider string
wantProvidersAttempted []string
wantErr error
badImplementation bool
}{
"success with metadata": {[]byte(`foobar`), "png", "test screenshot provider", []string{"test screenshot provider"}, nil, false},
"no implementations found": {nil, "", "", nil, &multierror.Error{Errors: []error{errors.New("not a ScreenshotGetter implementation: *struct {}"), errors.New("no ScreenshotGetter implementations found: error in provider implementation")}}, true},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := screenshotTester{}
generic = []interface{}{&testImplementation}
}
image, fileType, metadata, err := ScreenshotFromInterfaces(context.Background(), generic)
if err != nil {
if tc.wantErr == nil {
t.Fatal(err)
}
assert.Equal(t, tc.wantErr.Error(), err.Error())
} else {
assert.Equal(t, tc.wantImage, image)
assert.Equal(t, tc.wantFileType, fileType)
}
assert.Equal(t, tc.wantProvidersAttempted, metadata.ProvidersAttempted)
assert.Equal(t, tc.wantSuccessfulProvider, metadata.SuccessfulProvider)
})
}
}
================================================
FILE: bmc/sel.go
================================================
package bmc
import (
"context"
"fmt"
"time"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// System Event Log Services for related services
type SystemEventLog interface {
ClearSystemEventLog(ctx context.Context) (err error)
GetSystemEventLog(ctx context.Context) (entries [][]string, err error)
GetSystemEventLogRaw(ctx context.Context) (eventlog string, err error)
}
type systemEventLogProviders struct {
name string
systemEventLogProvider SystemEventLog
}
type SystemEventLogEntries [][]string
func clearSystemEventLog(ctx context.Context, timeout time.Duration, s []systemEventLogProviders) (metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range s {
if elem.systemEventLogProvider == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
selErr := elem.systemEventLogProvider.ClearSystemEventLog(ctx)
if selErr != nil {
err = multierror.Append(err, errors.WithMessagef(selErr, "provider: %v", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return metadataLocal, nil
}
}
return metadataLocal, multierror.Append(err, errors.New("failed to reset System Event Log"))
}
func ClearSystemEventLogFromInterfaces(ctx context.Context, timeout time.Duration, generic []interface{}) (metadata Metadata, err error) {
selServices := make([]systemEventLogProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := systemEventLogProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case SystemEventLog:
temp.systemEventLogProvider = p
selServices = append(selServices, temp)
default:
e := fmt.Sprintf("not a SystemEventLog service implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(selServices) == 0 {
return metadata, multierror.Append(err, errors.New("no SystemEventLog implementations found"))
}
return clearSystemEventLog(ctx, timeout, selServices)
}
func getSystemEventLog(ctx context.Context, timeout time.Duration, s []systemEventLogProviders) (sel SystemEventLogEntries, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range s {
if elem.systemEventLogProvider == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return sel, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
sel, selErr := elem.systemEventLogProvider.GetSystemEventLog(ctx)
if selErr != nil {
err = multierror.Append(err, errors.WithMessagef(selErr, "provider: %v", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return sel, metadataLocal, nil
}
}
return nil, metadataLocal, multierror.Append(err, errors.New("failed to get System Event Log"))
}
func GetSystemEventLogFromInterfaces(ctx context.Context, timeout time.Duration, generic []interface{}) (sel SystemEventLogEntries, metadata Metadata, err error) {
selServices := make([]systemEventLogProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := systemEventLogProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case SystemEventLog:
temp.systemEventLogProvider = p
selServices = append(selServices, temp)
default:
e := fmt.Sprintf("not a SystemEventLog service implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(selServices) == 0 {
return sel, metadata, multierror.Append(err, errors.New("no SystemEventLog implementations found"))
}
return getSystemEventLog(ctx, timeout, selServices)
}
func getSystemEventLogRaw(ctx context.Context, timeout time.Duration, s []systemEventLogProviders) (eventlog string, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range s {
if elem.systemEventLogProvider == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return eventlog, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
eventlog, selErr := elem.systemEventLogProvider.GetSystemEventLogRaw(ctx)
if selErr != nil {
err = multierror.Append(err, errors.WithMessagef(selErr, "provider: %v", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return eventlog, metadataLocal, nil
}
}
return eventlog, metadataLocal, multierror.Append(err, errors.New("failed to get System Event Log"))
}
func GetSystemEventLogRawFromInterfaces(ctx context.Context, timeout time.Duration, generic []interface{}) (eventlog string, metadata Metadata, err error) {
selServices := make([]systemEventLogProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := systemEventLogProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case SystemEventLog:
temp.systemEventLogProvider = p
selServices = append(selServices, temp)
default:
e := fmt.Sprintf("not a SystemEventLog service implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(selServices) == 0 {
return eventlog, metadata, multierror.Append(err, errors.New("no SystemEventLog implementations found"))
}
return getSystemEventLogRaw(ctx, timeout, selServices)
}
================================================
FILE: bmc/sel_test.go
================================================
package bmc
import (
"context"
"testing"
"time"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
type mockSystemEventLogService struct {
name string
err error
}
func (m *mockSystemEventLogService) ClearSystemEventLog(ctx context.Context) error {
return m.err
}
func (m *mockSystemEventLogService) GetSystemEventLog(ctx context.Context) (entries [][]string, err error) {
return nil, m.err
}
func (m *mockSystemEventLogService) GetSystemEventLogRaw(ctx context.Context) (eventlog string, err error) {
return "", m.err
}
func (m *mockSystemEventLogService) Name() string {
return m.name
}
func TestClearSystemEventLog(t *testing.T) {
ctx := context.Background()
timeout := 1 * time.Second
// Test with a mock SystemEventLogService that returns nil
mockService := &mockSystemEventLogService{name: "mock1", err: nil}
metadata, err := clearSystemEventLog(ctx, timeout, []systemEventLogProviders{{name: mockService.name, systemEventLogProvider: mockService}})
assert.Nil(t, err)
assert.Equal(t, mockService.name, metadata.SuccessfulProvider)
// Test with a mock SystemEventLogService that returns an error
mockService = &mockSystemEventLogService{name: "mock2", err: errors.New("mock error")}
metadata, err = clearSystemEventLog(ctx, timeout, []systemEventLogProviders{{name: mockService.name, systemEventLogProvider: mockService}})
assert.NotNil(t, err)
assert.NotEqual(t, mockService.name, metadata.SuccessfulProvider)
}
func TestClearSystemEventLogFromInterfaces(t *testing.T) {
ctx := context.Background()
timeout := 1 * time.Second
// Test with an empty slice
metadata, err := ClearSystemEventLogFromInterfaces(ctx, timeout, []interface{}{})
assert.NotNil(t, err)
assert.Empty(t, metadata.SuccessfulProvider)
// Test with a slice containing a non-SystemEventLog object
metadata, err = ClearSystemEventLogFromInterfaces(ctx, timeout, []interface{}{"not a SystemEventLog Service"})
assert.NotNil(t, err)
assert.Empty(t, metadata.SuccessfulProvider)
// Test with a slice containing a mock SystemEventLogService that returns nil
mockService := &mockSystemEventLogService{name: "mock1"}
metadata, err = ClearSystemEventLogFromInterfaces(ctx, timeout, []interface{}{mockService})
assert.Nil(t, err)
assert.Equal(t, mockService.name, metadata.SuccessfulProvider)
}
func TestGetSystemEventLog(t *testing.T) {
ctx := context.Background()
timeout := 1 * time.Second
// Test with a mock SystemEventLogService that returns nil
mockService := &mockSystemEventLogService{name: "mock1", err: nil}
_, _, err := getSystemEventLog(ctx, timeout, []systemEventLogProviders{{name: mockService.name, systemEventLogProvider: mockService}})
assert.Nil(t, err)
// Test with a mock SystemEventLogService that returns an error
mockService = &mockSystemEventLogService{name: "mock2", err: errors.New("mock error")}
_, _, err = getSystemEventLog(ctx, timeout, []systemEventLogProviders{{name: mockService.name, systemEventLogProvider: mockService}})
assert.NotNil(t, err)
}
func TestGetSystemEventLogFromInterfaces(t *testing.T) {
ctx := context.Background()
timeout := 1 * time.Second
// Test with an empty slice
_, _, err := GetSystemEventLogFromInterfaces(ctx, timeout, []interface{}{})
assert.NotNil(t, err)
// Test with a slice containing a non-SystemEventLog object
_, _, err = GetSystemEventLogFromInterfaces(ctx, timeout, []interface{}{"not a SystemEventLog Service"})
assert.NotNil(t, err)
// Test with a slice containing a mock SystemEventLogService that returns nil
mockService := &mockSystemEventLogService{name: "mock1"}
_, _, err = GetSystemEventLogFromInterfaces(ctx, timeout, []interface{}{mockService})
assert.Nil(t, err)
}
func TestGetSystemEventLogRaw(t *testing.T) {
ctx := context.Background()
timeout := 1 * time.Second
// Test with a mock SystemEventLogService that returns nil
mockService := &mockSystemEventLogService{name: "mock1", err: nil}
_, _, err := getSystemEventLogRaw(ctx, timeout, []systemEventLogProviders{{name: mockService.name, systemEventLogProvider: mockService}})
assert.Nil(t, err)
// Test with a mock SystemEventLogService that returns an error
mockService = &mockSystemEventLogService{name: "mock2", err: errors.New("mock error")}
_, _, err = getSystemEventLogRaw(ctx, timeout, []systemEventLogProviders{{name: mockService.name, systemEventLogProvider: mockService}})
assert.NotNil(t, err)
}
func TestGetSystemEventLogRawFromInterfaces(t *testing.T) {
ctx := context.Background()
timeout := 1 * time.Second
// Test with an empty slice
_, _, err := GetSystemEventLogRawFromInterfaces(ctx, timeout, []interface{}{})
assert.NotNil(t, err)
// Test with a slice containing a non-SystemEventLog object
_, _, err = GetSystemEventLogRawFromInterfaces(ctx, timeout, []interface{}{"not a SystemEventLog Service"})
assert.NotNil(t, err)
// Test with a slice containing a mock SystemEventLogService that returns nil
mockService := &mockSystemEventLogService{name: "mock1"}
_, _, err = GetSystemEventLogRawFromInterfaces(ctx, timeout, []interface{}{mockService})
assert.Nil(t, err)
}
================================================
FILE: bmc/sol.go
================================================
package bmc
import (
"context"
"fmt"
"time"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// SOLDeactivator for deactivating SOL sessions on a BMC.
type SOLDeactivator interface {
DeactivateSOL(ctx context.Context) (err error)
}
// deactivatorProvider is an internal struct to correlate an implementation/provider and its name
type deactivatorProvider struct {
name string
solDeactivator SOLDeactivator
}
// deactivateSOL tries all implementations for a successful SOL deactivation
func deactivateSOL(ctx context.Context, timeout time.Duration, b []deactivatorProvider) (metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range b {
if elem.solDeactivator == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
newErr := elem.solDeactivator.DeactivateSOL(ctx)
if newErr != nil {
err = multierror.Append(err, errors.WithMessagef(newErr, "provider: %v", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return metadataLocal, nil
}
}
return metadataLocal, multierror.Append(err, errors.New("failed to deactivate SOL session"))
}
// DeactivateSOLFromInterfaces identifies implementations of the SOLDeactivator interface and passes them to the deactivateSOL() wrapper method.
func DeactivateSOLFromInterfaces(ctx context.Context, timeout time.Duration, generic []interface{}) (metadata Metadata, err error) {
deactivators := make([]deactivatorProvider, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := deactivatorProvider{name: getProviderName(elem)}
switch p := elem.(type) {
case SOLDeactivator:
temp.solDeactivator = p
deactivators = append(deactivators, temp)
default:
e := fmt.Sprintf("not an SOLDeactivator implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(deactivators) == 0 {
return metadata, multierror.Append(err, errors.New("no SOLDeactivator implementations found"))
}
return deactivateSOL(ctx, timeout, deactivators)
}
================================================
FILE: bmc/sol_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
)
type solTermTester struct {
MakeErrorOut bool
}
func (r *solTermTester) DeactivateSOL(ctx context.Context) (err error) {
if r.MakeErrorOut {
return errors.New("SOL deactivation failed")
}
return nil
}
func (r *solTermTester) Name() string {
return "test provider"
}
func TestDeactivateSOL(t *testing.T) {
testCases := map[string]struct {
makeErrorOut bool
err error
ctxTimeout time.Duration
}{
"success": {makeErrorOut: false},
"error": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("provider: test provider: SOL deactivation failed"), errors.New("failed to deactivate SOL session")}}},
"error context timeout": {makeErrorOut: false, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := solTermTester{MakeErrorOut: tc.makeErrorOut}
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
_, err := deactivateSOL(ctx, 0, []deactivatorProvider{{"test provider", &testImplementation}})
var diff string
if err != nil && tc.err != nil {
diff = cmp.Diff(err.Error(), tc.err.Error())
} else {
diff = cmp.Diff(err, tc.err)
}
if diff != "" {
t.Fatal(diff)
}
})
}
}
func TestDeactivateSOLFromInterfaces(t *testing.T) {
testCases := map[string]struct {
err error
badImplementation bool
withName bool
}{
"success": {},
"success with metadata": {withName: true},
"no implementations found": {badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not an SOLDeactivator implementation: *struct {}"), errors.New("no SOLDeactivator implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := solTermTester{}
generic = []interface{}{&testImplementation}
}
metadata, err := DeactivateSOLFromInterfaces(context.Background(), 0, generic)
var diff string
if err != nil && tc.err != nil {
diff = cmp.Diff(err.Error(), tc.err.Error())
} else {
diff = cmp.Diff(err, tc.err)
}
if diff != "" {
t.Fatal(diff)
}
if tc.withName {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
================================================
FILE: bmc/user.go
================================================
package bmc
import (
"context"
"errors"
"fmt"
"time"
"github.com/hashicorp/go-multierror"
)
// UserCreator creates a user on a BMC
type UserCreator interface {
UserCreate(ctx context.Context, user, pass, role string) (ok bool, err error)
}
// UserUpdater updates a user on a BMC
type UserUpdater interface {
UserUpdate(ctx context.Context, user, pass, role string) (ok bool, err error)
}
// UserDeleter deletes a user on a BMC
type UserDeleter interface {
UserDelete(ctx context.Context, user string) (ok bool, err error)
}
// UserReader lists all users on a BMC
type UserReader interface {
UserRead(ctx context.Context) (users []map[string]string, err error)
}
// userProviders is an internal struct used to correlate an implementation/provider with its name
type userProviders struct {
name string
userCreator UserCreator
userUpdater UserUpdater
userDeleter UserDeleter
userReader UserReader
}
// createUser creates a user using the passed in implementation
func createUser(ctx context.Context, timeout time.Duration, user, pass, role string, u []userProviders) (ok bool, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range u {
if elem.userCreator == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return false, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
ok, createErr := elem.userCreator.UserCreate(ctx, user, pass, role)
if createErr != nil {
err = multierror.Append(err, createErr)
continue
}
if !ok {
err = multierror.Append(err, errors.New("failed to create user"))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return ok, metadataLocal, nil
}
}
return ok, metadataLocal, multierror.Append(err, errors.New("failed to create user"))
}
// CreateUsersFromInterfaces identifies implementations of the UserCreator interface and passes them to the createUser() wrapper method.
func CreateUserFromInterfaces(ctx context.Context, timeout time.Duration, user, pass, role string, generic []interface{}) (ok bool, metadata Metadata, err error) {
userCreators := make([]userProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := userProviders{name: getProviderName(elem)}
switch u := elem.(type) {
case UserCreator:
temp.userCreator = u
userCreators = append(userCreators, temp)
default:
e := fmt.Sprintf("not a UserCreator implementation: %T", u)
err = multierror.Append(err, errors.New(e))
}
}
if len(userCreators) == 0 {
return ok, metadata, multierror.Append(err, errors.New("no UserCreator implementations found"))
}
return createUser(ctx, timeout, user, pass, role, userCreators)
}
// updateUser updates a user's settings
func updateUser(ctx context.Context, timeout time.Duration, user, pass, role string, u []userProviders) (ok bool, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range u {
if elem.userUpdater == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return false, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
ok, UpdateErr := elem.userUpdater.UserUpdate(ctx, user, pass, role)
if UpdateErr != nil {
err = multierror.Append(err, UpdateErr)
continue
}
if !ok {
err = multierror.Append(err, errors.New("failed to update user"))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return ok, metadataLocal, nil
}
}
return ok, metadataLocal, multierror.Append(err, errors.New("failed to update user"))
}
// UpdateUsersFromInterfaces identifies implementations of the UserUpdater interface and passes them to the updateUser() wrapper method.
func UpdateUserFromInterfaces(ctx context.Context, timeout time.Duration, user, pass, role string, generic []interface{}) (ok bool, metadata Metadata, err error) {
userUpdaters := make([]userProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := userProviders{name: getProviderName(elem)}
switch u := elem.(type) {
case UserUpdater:
temp.userUpdater = u
userUpdaters = append(userUpdaters, temp)
default:
e := fmt.Sprintf("not a UserUpdater implementation: %T", u)
err = multierror.Append(err, errors.New(e))
}
}
if len(userUpdaters) == 0 {
return ok, metadata, multierror.Append(err, errors.New("no UserUpdater implementations found"))
}
return updateUser(ctx, timeout, user, pass, role, userUpdaters)
}
// deleteUser deletes a user from a BMC
func deleteUser(ctx context.Context, timeout time.Duration, user string, u []userProviders) (ok bool, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range u {
if elem.userDeleter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return false, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
ok, deleteErr := elem.userDeleter.UserDelete(ctx, user)
if deleteErr != nil {
err = multierror.Append(err, deleteErr)
continue
}
if !ok {
err = multierror.Append(err, errors.New("failed to delete user"))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return ok, metadataLocal, nil
}
}
return ok, metadataLocal, multierror.Append(err, errors.New("failed to delete user"))
}
// DeleteUsersFromInterfaces identifies implementations of the UserDeleter interface and passes them to the deleteUser() wrapper method.
func DeleteUserFromInterfaces(ctx context.Context, timeout time.Duration, user string, generic []interface{}) (ok bool, metadata Metadata, err error) {
userDeleters := make([]userProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := userProviders{name: getProviderName(elem)}
switch u := elem.(type) {
case UserDeleter:
temp.userDeleter = u
userDeleters = append(userDeleters, temp)
default:
e := fmt.Sprintf("not a UserDeleter implementation: %T", u)
err = multierror.Append(err, errors.New(e))
}
}
if len(userDeleters) == 0 {
return ok, metadata, multierror.Append(err, errors.New("no UserDeleter implementations found"))
}
return deleteUser(ctx, timeout, user, userDeleters)
}
// readUsers returns all users from a BMC
func readUsers(ctx context.Context, timeout time.Duration, u []userProviders) (users []map[string]string, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range u {
if elem.userReader == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return users, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
users, readErr := elem.userReader.UserRead(ctx)
if readErr != nil {
err = multierror.Append(err, readErr)
continue
}
metadataLocal.SuccessfulProvider = elem.name
return users, metadataLocal, nil
}
}
return users, metadataLocal, multierror.Append(err, errors.New("failed to read users"))
}
// ReadUsersFromInterfaces identifies implementations of the UserReader interface and passes them to the readUsers() wrapper method.
func ReadUsersFromInterfaces(ctx context.Context, timeout time.Duration, generic []interface{}) (users []map[string]string, metadata Metadata, err error) {
userReaders := make([]userProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := userProviders{name: getProviderName(elem)}
switch u := elem.(type) {
case UserReader:
temp.userReader = u
userReaders = append(userReaders, temp)
default:
e := fmt.Sprintf("not a UserReader implementation: %T", u)
err = multierror.Append(errors.New(e))
}
}
if len(userReaders) == 0 {
return users, metadata, multierror.Append(err, errors.New("no UserReader implementations found"))
}
return readUsers(ctx, timeout, userReaders)
}
================================================
FILE: bmc/user_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
)
type userTester struct {
MakeNotOK bool
MakeErrorOut bool
}
func (p *userTester) UserCreate(ctx context.Context, user, pass, role string) (ok bool, err error) {
if p.MakeErrorOut {
return ok, errors.New("create user failed")
}
if p.MakeNotOK {
return false, nil
}
return true, nil
}
func (p *userTester) UserUpdate(ctx context.Context, user, pass, role string) (ok bool, err error) {
if p.MakeErrorOut {
return ok, errors.New("update user failed")
}
if p.MakeNotOK {
return false, nil
}
return true, nil
}
func (p *userTester) UserDelete(ctx context.Context, user string) (ok bool, err error) {
if p.MakeErrorOut {
return ok, errors.New("delete user failed")
}
if p.MakeNotOK {
return false, nil
}
return true, nil
}
func (p *userTester) UserRead(ctx context.Context) (users []map[string]string, err error) {
if p.MakeErrorOut {
return users, errors.New("read users failed")
}
users = []map[string]string{
{
"Auth": "true",
"Callin": "true",
"ID": "2",
"Link": "false",
"Name": "ADMIN",
},
}
return users, nil
}
func (p *userTester) Name() string {
return "test provider"
}
func TestUserCreate(t *testing.T) {
testCases := map[string]struct {
makeErrorOut bool
makeNotOk bool
want bool
err error
ctxTimeout time.Duration
}{
"success": {want: true},
"not ok return": {want: false, makeNotOk: true, err: &multierror.Error{Errors: []error{errors.New("failed to create user"), errors.New("failed to create user")}}},
"error": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("create user failed"), errors.New("failed to create user")}}},
"error context timeout": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := userTester{MakeErrorOut: tc.makeErrorOut, MakeNotOK: tc.makeNotOk}
expectedResult := tc.want
user := "ADMIN"
pass := "ADMIN"
role := "admin"
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := createUser(ctx, 0, user, pass, role, []userProviders{{"", &testImplementation, nil, nil, nil}})
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestCreateUserFromInterfaces(t *testing.T) {
testCases := map[string]struct {
err error
badImplementation bool
want bool
withMetadata bool
}{
"success": {want: true},
"success with metadata": {want: true, withMetadata: true},
"no implementations found": {badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a UserCreator implementation: *struct {}"), errors.New("no UserCreator implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := userTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := tc.want
user := "ADMIN"
pass := "ADMIN"
role := "admin"
result, metadata, err := CreateUserFromInterfaces(context.Background(), 0, user, pass, role, generic)
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Logf("%+v", metadata)
t.Fatal(diff)
}
}
})
}
}
func TestUpdateUser(t *testing.T) {
testCases := map[string]struct {
makeErrorOut bool
makeNotOk bool
want bool
err error
ctxTimeout time.Duration
}{
"success": {want: true},
"not ok return": {want: false, makeNotOk: true, err: &multierror.Error{Errors: []error{errors.New("failed to update user"), errors.New("failed to update user")}}},
"error": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("update user failed"), errors.New("failed to update user")}}},
"error context timeout": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := userTester{MakeErrorOut: tc.makeErrorOut, MakeNotOK: tc.makeNotOk}
expectedResult := tc.want
user := "ADMIN"
pass := "ADMIN"
role := "admin"
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := updateUser(ctx, 0, user, pass, role, []userProviders{{"", nil, &testImplementation, nil, nil}})
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestUpdateUserFromInterfaces(t *testing.T) {
testCases := map[string]struct {
err error
badImplementation bool
want bool
withMetadata bool
}{
"success": {want: true},
"success with metadata": {want: true, withMetadata: true},
"no implementations found": {badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a UserUpdater implementation: *struct {}"), errors.New("no UserUpdater implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := userTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := tc.want
user := "ADMIN"
pass := "ADMIN"
role := "admin"
result, metadata, err := UpdateUserFromInterfaces(context.Background(), 0, user, pass, role, generic)
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestDeleteUser(t *testing.T) {
testCases := map[string]struct {
makeErrorOut bool
makeNotOk bool
want bool
err error
ctxTimeout time.Duration
}{
"success": {want: true},
"not ok return": {want: false, makeNotOk: true, err: &multierror.Error{Errors: []error{errors.New("failed to delete user"), errors.New("failed to delete user")}}},
"error": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("delete user failed"), errors.New("failed to delete user")}}},
"error context timeout": {makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := userTester{MakeErrorOut: tc.makeErrorOut, MakeNotOK: tc.makeNotOk}
expectedResult := tc.want
user := "ADMIN"
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := deleteUser(ctx, 0, user, []userProviders{{"", nil, nil, &testImplementation, nil}})
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestDeleteUserFromInterfaces(t *testing.T) {
testCases := map[string]struct {
err error
badImplementation bool
want bool
withMetadata bool
}{
"success": {want: true},
"success with metadata": {want: true, withMetadata: true},
"no implementations found": {badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a UserDeleter implementation: *struct {}"), errors.New("no UserDeleter implementations found")}}},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := userTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := tc.want
user := "ADMIN"
result, metadata, err := DeleteUserFromInterfaces(context.Background(), 0, user, generic)
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestReadUsers(t *testing.T) {
testCases := map[string]struct {
makeErrorOut bool
want bool
err error
ctxTimeout time.Duration
}{
"success": {want: true},
"not ok return": {want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("read users failed"), errors.New("failed to read users")}}},
"error context timeout": {want: false, makeErrorOut: true, err: &multierror.Error{Errors: []error{errors.New("context deadline exceeded")}}, ctxTimeout: time.Nanosecond * 1},
}
users := []map[string]string{
{
"Auth": "true",
"Callin": "true",
"ID": "2",
"Link": "false",
"Name": "ADMIN",
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
testImplementation := userTester{MakeErrorOut: tc.makeErrorOut}
expectedResult := users
if tc.ctxTimeout == 0 {
tc.ctxTimeout = time.Second * 3
}
ctx, cancel := context.WithTimeout(context.Background(), tc.ctxTimeout)
defer cancel()
result, _, err := readUsers(ctx, 0, []userProviders{{"", nil, nil, nil, &testImplementation}})
if err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
})
}
}
func TestReadUsersFromInterfaces(t *testing.T) {
testCases := map[string]struct {
err error
badImplementation bool
want bool
withMetadata bool
}{
"success": {want: true},
"success with metadata": {want: true, withMetadata: true},
"no implementations found": {badImplementation: true, err: &multierror.Error{Errors: []error{errors.New("not a UserReader implementation: *struct {}"), errors.New("no UserReader implementations found")}}},
}
users := []map[string]string{
{
"Auth": "true",
"Callin": "true",
"ID": "2",
"Link": "false",
"Name": "ADMIN",
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
var generic []interface{}
if tc.badImplementation {
badImplementation := struct{}{}
generic = []interface{}{&badImplementation}
} else {
testImplementation := userTester{}
generic = []interface{}{&testImplementation}
}
expectedResult := users
result, metadata, err := ReadUsersFromInterfaces(context.Background(), 0, generic)
if err != nil {
if tc.err != nil {
diff := cmp.Diff(err.Error(), tc.err.Error())
if diff != "" {
t.Fatal(diff)
}
} else {
t.Fatal(err)
}
} else {
diff := cmp.Diff(result, expectedResult)
if diff != "" {
t.Fatal(diff)
}
}
if tc.withMetadata {
if diff := cmp.Diff(metadata.SuccessfulProvider, "test provider"); diff != "" {
t.Fatal(diff)
}
}
})
}
}
================================================
FILE: bmc/virtual_media.go
================================================
package bmc
import (
"context"
"fmt"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
)
// VirtualMediaSetter controls the virtual media attached to a machine
type VirtualMediaSetter interface {
SetVirtualMedia(ctx context.Context, kind string, mediaURL string) (ok bool, err error)
}
// VirtualMediaProviders is an internal struct to correlate an implementation/provider and its name
type virtualMediaProviders struct {
name string
virtualMediaSetter VirtualMediaSetter
}
// setVirtualMedia sets the virtual media.
func setVirtualMedia(ctx context.Context, kind string, mediaURL string, b []virtualMediaProviders) (ok bool, metadata Metadata, err error) {
var metadataLocal Metadata
for _, elem := range b {
if elem.virtualMediaSetter == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
return false, metadata, err
default:
metadataLocal.ProvidersAttempted = append(metadataLocal.ProvidersAttempted, elem.name)
ok, setErr := elem.virtualMediaSetter.SetVirtualMedia(ctx, kind, mediaURL)
if setErr != nil {
err = multierror.Append(err, errors.WithMessagef(setErr, "provider: %v", elem.name))
continue
}
if !ok {
err = multierror.Append(err, fmt.Errorf("provider: %v, failed to set virtual media", elem.name))
continue
}
metadataLocal.SuccessfulProvider = elem.name
return ok, metadataLocal, nil
}
}
return ok, metadataLocal, multierror.Append(err, errors.New("failed to set virtual media"))
}
// SetVirtualMediaFromInterfaces identifies implementations of the virtualMediaSetter interface and passes the found implementations to the setVirtualMedia() wrapper
func SetVirtualMediaFromInterfaces(ctx context.Context, kind string, mediaURL string, generic []interface{}) (ok bool, metadata Metadata, err error) {
bdSetters := make([]virtualMediaProviders, 0)
for _, elem := range generic {
if elem == nil {
continue
}
temp := virtualMediaProviders{name: getProviderName(elem)}
switch p := elem.(type) {
case VirtualMediaSetter:
temp.virtualMediaSetter = p
bdSetters = append(bdSetters, temp)
default:
e := fmt.Sprintf("not a VirtualMediaSetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(bdSetters) == 0 {
return ok, metadata, multierror.Append(err, errors.New("no VirtualMediaSetter implementations found"))
}
return setVirtualMedia(ctx, kind, mediaURL, bdSetters)
}
================================================
FILE: bmc/virtual_media_test.go
================================================
package bmc
import (
"context"
"errors"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/go-multierror"
)
type v
gitextract_jzsoh1mg/
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── default.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── mergify.yml
│ └── workflows/
│ └── ci.yaml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── Makefile
├── README.md
├── bmc/
│ ├── bios.go
│ ├── bmc.go
│ ├── boot_device.go
│ ├── boot_device_test.go
│ ├── connection.go
│ ├── connection_test.go
│ ├── firmware.go
│ ├── firmware_test.go
│ ├── floppy.go
│ ├── floppy_test.go
│ ├── inventory.go
│ ├── inventory_test.go
│ ├── nmi.go
│ ├── nmi_test.go
│ ├── postcode.go
│ ├── postcode_test.go
│ ├── power.go
│ ├── power_test.go
│ ├── provider.go
│ ├── reset.go
│ ├── reset_test.go
│ ├── screenshot.go
│ ├── screenshot_test.go
│ ├── sel.go
│ ├── sel_test.go
│ ├── sol.go
│ ├── sol_test.go
│ ├── user.go
│ ├── user_test.go
│ ├── virtual_media.go
│ └── virtual_media_test.go
├── client.go
├── client_test.go
├── constants/
│ └── constants.go
├── doc.go
├── errors/
│ └── errors.go
├── examples/
│ ├── bios/
│ │ ├── doc.go
│ │ └── main.go
│ ├── create-users/
│ │ ├── doc.go
│ │ └── main.go
│ ├── floppy-image/
│ │ ├── doc.go
│ │ └── main.go
│ ├── homeassistant/
│ │ └── main.go
│ ├── install-firmware/
│ │ ├── doc.go
│ │ └── main.go
│ ├── inventory/
│ │ ├── doc.go
│ │ ├── main.go
│ │ └── output.json
│ ├── reset_bmc/
│ │ └── reset_bmc.go
│ ├── rpc/
│ │ └── main.go
│ ├── screenshot/
│ │ ├── doc.go
│ │ └── main.go
│ ├── sel/
│ │ └── main.go
│ ├── status/
│ │ ├── doc.go
│ │ └── main.go
│ └── virtualmedia/
│ ├── doc.go
│ └── main.go
├── filter.go
├── fixtures/
│ └── internal/
│ └── sum/
│ ├── ChangeBiosConfig
│ ├── ChangeBiosConfig-Changed
│ ├── ChangeBiosConfig-Changed-Reboot
│ ├── GetBIOSInfo
│ ├── GetBiosConfiguration
│ └── SetBiosConfiguration
├── go.mod
├── go.sum
├── internal/
│ ├── executor/
│ │ ├── errors.go
│ │ ├── executor.go
│ │ ├── executor_test.go
│ │ └── fake_executor.go
│ ├── helper/
│ │ ├── helper.go
│ │ └── helper_test.go
│ ├── httpclient/
│ │ ├── httpclient.go
│ │ └── httpclient_test.go
│ ├── ipmi/
│ │ └── ipmi.go
│ ├── redfishwrapper/
│ │ ├── bios.go
│ │ ├── bios_test.go
│ │ ├── boot_device.go
│ │ ├── client.go
│ │ ├── client_test.go
│ │ ├── firmware.go
│ │ ├── firmware_test.go
│ │ ├── fixtures/
│ │ │ ├── dell/
│ │ │ │ ├── bios.json
│ │ │ │ ├── manager.idrac.embedded.1.json
│ │ │ │ ├── managers.json
│ │ │ │ ├── serviceroot.json
│ │ │ │ ├── system.embedded.1.json
│ │ │ │ ├── system.embedded.1.virtualmedia.json
│ │ │ │ ├── systems.json
│ │ │ │ ├── virtualmedia_1.json
│ │ │ │ ├── virtualmedia_2.json
│ │ │ │ └── virtualmedia_collection.json
│ │ │ ├── managers.json
│ │ │ ├── managers_1.json
│ │ │ ├── serviceroot.json
│ │ │ ├── serviceroot_no_manager.json
│ │ │ ├── smc_1.14.0_serviceroot.json
│ │ │ ├── smc_1.14.0_systems.json
│ │ │ ├── smc_1.14.0_systems_1.json
│ │ │ ├── smc_1.9.0_serviceroot.json
│ │ │ ├── systems.json
│ │ │ ├── systems_1.json
│ │ │ ├── systems_1_no_bios.json
│ │ │ ├── systems_bios.json
│ │ │ ├── tasks/
│ │ │ │ ├── tasks_1_completed.json
│ │ │ │ ├── tasks_1_failed.json
│ │ │ │ ├── tasks_1_pending.json
│ │ │ │ ├── tasks_1_running.json
│ │ │ │ ├── tasks_1_scheduled.json
│ │ │ │ ├── tasks_1_starting.json
│ │ │ │ ├── tasks_1_unknown.json
│ │ │ │ └── tasks_2.json
│ │ │ ├── tasks.json
│ │ │ ├── taskservice.json
│ │ │ ├── updateservice_disabled.json
│ │ │ ├── updateservice_ok_response.json
│ │ │ ├── updateservice_unexpected_response.json
│ │ │ ├── updateservice_with_httppushuri.json
│ │ │ └── updateservice_with_multipart.json
│ │ ├── inventory.go
│ │ ├── inventory_collect.go
│ │ ├── inventory_collect_test.go
│ │ ├── main_test.go
│ │ ├── power.go
│ │ ├── sel.go
│ │ ├── system.go
│ │ ├── system_test.go
│ │ ├── task.go
│ │ ├── task_test.go
│ │ ├── virtual_media.go
│ │ └── virtual_media_test.go
│ ├── sum/
│ │ ├── sum.go
│ │ └── sum_test.go
│ └── utils.go
├── lint.mk
├── logging/
│ └── logging.go
├── option.go
└── providers/
├── asrockrack/
│ ├── asrockrack.go
│ ├── asrockrack_test.go
│ ├── firmware.go
│ ├── firmware_update.md
│ ├── fixtures/
│ │ └── E3C246D4I-NL/
│ │ └── sensors.json
│ ├── helpers.go
│ ├── helpers_test.go
│ ├── inventory.go
│ ├── inventory_test.go
│ ├── mock_test.go
│ ├── power.go
│ ├── user.go
│ └── user_test.go
├── dell/
│ ├── firmware.go
│ ├── firmware_test.go
│ ├── fixtures/
│ │ ├── serviceroot.json
│ │ ├── systems.json
│ │ ├── systems_embedded.1.json
│ │ ├── systems_embedded_no_manufacturer.1.json
│ │ └── systems_embedded_not_dell.1.json
│ ├── idrac.go
│ └── idrac_test.go
├── homeassistant/
│ └── homeassistant.go
├── intelamt/
│ ├── intelamt.go
│ └── intelamt_test.go
├── ipmitool/
│ ├── ipmitool.go
│ └── ipmitool_test.go
├── openbmc/
│ ├── firmware.go
│ └── openbmc.go
├── providers.go
├── redfish/
│ ├── fixtures/
│ │ └── v1/
│ │ ├── dell/
│ │ │ ├── entries.json
│ │ │ ├── job_delete_ok.json
│ │ │ ├── jobs.json
│ │ │ ├── logservices.json
│ │ │ ├── logservices.sel.json
│ │ │ ├── manager.idrac.embedded.1.json
│ │ │ ├── managers.json
│ │ │ └── selentries/
│ │ │ ├── 1.json
│ │ │ └── 2.json
│ │ ├── serviceroot.json
│ │ ├── systems.json
│ │ └── updateservice.json
│ ├── main_test.go
│ ├── redfish.go
│ ├── sel.go
│ ├── sel_test.go
│ └── user.go
├── rpc/
│ ├── doc.go
│ ├── experimental.go
│ ├── http.go
│ ├── http_test.go
│ ├── logging.go
│ ├── payload.go
│ ├── rpc.go
│ ├── rpc_test.go
│ └── signature.go
└── supermicro/
├── docs/
│ ├── x11.md
│ └── x12.md
├── errors.go
├── firmware.go
├── firmware_bios_test.go
├── fixtures/
│ └── serviceroot.json
├── floppy.go
├── supermicro.go
├── supermicro_test.go
├── types.go
├── x11.go
├── x11_firmware_bios.go
├── x11_firmware_bmc.go
├── x11_firmware_bmc_test.go
└── x12.go
SYMBOL INDEX (1161 symbols across 129 files)
FILE: bmc/bios.go
type BiosConfigurationGetter (line 12) | type BiosConfigurationGetter interface
type biosConfigurationGetterProvider (line 16) | type biosConfigurationGetterProvider struct
type BiosConfigurationSetter (line 21) | type BiosConfigurationSetter interface
type biosConfigurationSetterProvider (line 26) | type biosConfigurationSetterProvider struct
type BiosConfigurationResetter (line 31) | type BiosConfigurationResetter interface
type biosConfigurationResetterProvider (line 35) | type biosConfigurationResetterProvider struct
function biosConfiguration (line 40) | func biosConfiguration(ctx context.Context, generic []biosConfigurationG...
function setBiosConfiguration (line 68) | func setBiosConfiguration(ctx context.Context, generic []biosConfigurati...
function setBiosConfigurationFromFile (line 96) | func setBiosConfigurationFromFile(ctx context.Context, generic []biosCon...
function resetBiosConfiguration (line 124) | func resetBiosConfiguration(ctx context.Context, generic []biosConfigura...
function GetBiosConfigurationInterfaces (line 152) | func GetBiosConfigurationInterfaces(ctx context.Context, generic []inter...
function SetBiosConfigurationInterfaces (line 181) | func SetBiosConfigurationInterfaces(ctx context.Context, generic []inter...
function SetBiosConfigurationFromFileInterfaces (line 210) | func SetBiosConfigurationFromFileInterfaces(ctx context.Context, generic...
function ResetBiosConfigurationInterfaces (line 239) | func ResetBiosConfigurationInterfaces(ctx context.Context, generic []int...
FILE: bmc/bmc.go
type Metadata (line 11) | type Metadata struct
method RegisterSpanAttributes (line 30) | func (m *Metadata) RegisterSpanAttributes(host string, span trace.Span) {
function newMetadata (line 24) | func newMetadata() Metadata {
FILE: bmc/boot_device.go
type BootDeviceType (line 12) | type BootDeviceType
constant BootDeviceTypeBIOS (line 15) | BootDeviceTypeBIOS BootDeviceType = "bios"
constant BootDeviceTypeCDROM (line 16) | BootDeviceTypeCDROM BootDeviceType = "cdrom"
constant BootDeviceTypeDiag (line 17) | BootDeviceTypeDiag BootDeviceType = "diag"
constant BootDeviceTypeFloppy (line 18) | BootDeviceTypeFloppy BootDeviceType = "floppy"
constant BootDeviceTypeDisk (line 19) | BootDeviceTypeDisk BootDeviceType = "disk"
constant BootDeviceTypeNone (line 20) | BootDeviceTypeNone BootDeviceType = "none"
constant BootDeviceTypePXE (line 21) | BootDeviceTypePXE BootDeviceType = "pxe"
constant BootDeviceTypeRemoteDrive (line 22) | BootDeviceTypeRemoteDrive BootDeviceType = "remote_drive"
constant BootDeviceTypeSDCard (line 23) | BootDeviceTypeSDCard BootDeviceType = "sd_card"
constant BootDeviceTypeUSB (line 24) | BootDeviceTypeUSB BootDeviceType = "usb"
constant BootDeviceTypeUtil (line 25) | BootDeviceTypeUtil BootDeviceType = "utilities"
constant BootDeviceUefiHTTP (line 26) | BootDeviceUefiHTTP BootDeviceType = "uefi_http"
type BootDeviceSetter (line 30) | type BootDeviceSetter interface
type BootDeviceOverrideGetter (line 35) | type BootDeviceOverrideGetter interface
type bootDeviceProviders (line 40) | type bootDeviceProviders struct
type bootOverrideProvider (line 46) | type bootOverrideProvider struct
type BootDeviceOverride (line 51) | type BootDeviceOverride struct
function setBootDevice (line 61) | func setBootDevice(ctx context.Context, timeout time.Duration, bootDevic...
function SetBootDeviceFromInterfaces (line 95) | func SetBootDeviceFromInterfaces(ctx context.Context, timeout time.Durat...
function getBootDeviceOverride (line 119) | func getBootDeviceOverride(
function GetBootDeviceOverrideFromInterface (line 147) | func GetBootDeviceOverrideFromInterface(
FILE: bmc/boot_device_test.go
type bootDeviceTester (line 15) | type bootDeviceTester struct
method BootDeviceSet (line 20) | func (b *bootDeviceTester) BootDeviceSet(ctx context.Context, bootDevi...
method Name (line 30) | func (b *bootDeviceTester) Name() string {
function TestSetBootDevice (line 34) | func TestSetBootDevice(t *testing.T) {
function TestSetBootDeviceFromInterfaces (line 78) | func TestSetBootDeviceFromInterfaces(t *testing.T) {
type mockBootDeviceOverrideGetter (line 123) | type mockBootDeviceOverrideGetter struct
method Name (line 128) | func (m *mockBootDeviceOverrideGetter) Name() string {
method BootDeviceOverrideGet (line 132) | func (m *mockBootDeviceOverrideGetter) BootDeviceOverrideGet(_ context...
function TestBootDeviceOverrideGet (line 136) | func TestBootDeviceOverrideGet(t *testing.T) {
FILE: bmc/connection.go
type Opener (line 14) | type Opener interface
type Closer (line 19) | type Closer interface
type connectionProviders (line 24) | type connectionProviders struct
function OpenConnectionFromInterfaces (line 32) | func OpenConnectionFromInterfaces(ctx context.Context, timeout time.Dura...
function closeConnection (line 114) | func closeConnection(ctx context.Context, c []connectionProviders) (meta...
function CloseConnectionFromInterfaces (line 139) | func CloseConnectionFromInterfaces(ctx context.Context, generic []interf...
FILE: bmc/connection_test.go
type connTester1 (line 14) | type connTester1 struct
method Open (line 18) | func (r *connTester1) Open(ctx context.Context) (err error) {
method Close (line 25) | func (r *connTester1) Close(ctx context.Context) (err error) {
method Name (line 32) | func (p *connTester1) Name() string {
type connTester2 (line 36) | type connTester2 struct
method Open (line 38) | func (r *connTester2) Open(ctx context.Context) (err error) {
method Close (line 43) | func (r *connTester2) Close(ctx context.Context) (err error) {
method Name (line 47) | func (p *connTester2) Name() string {
function TestOpenConnectionFromInterfaces (line 51) | func TestOpenConnectionFromInterfaces(t *testing.T) {
function TestCloseConnection (line 117) | func TestCloseConnection(t *testing.T) {
function TestCloseConnectionFromInterfaces (line 147) | func TestCloseConnectionFromInterfaces(t *testing.T) {
FILE: bmc/firmware.go
type FirmwareInstaller (line 18) | type FirmwareInstaller interface
type firmwareInstallerProvider (line 33) | type firmwareInstallerProvider struct
function firmwareInstall (line 39) | func firmwareInstall(ctx context.Context, component, operationApplyTime ...
function FirmwareInstallFromInterfaces (line 69) | func FirmwareInstallFromInterfaces(ctx context.Context, component, opera...
type FirmwareInstallVerifier (line 103) | type FirmwareInstallVerifier interface
type firmwareInstallVerifierProvider (line 117) | type firmwareInstallVerifierProvider struct
function firmwareInstallStatus (line 123) | func firmwareInstallStatus(ctx context.Context, installVersion, componen...
function FirmwareInstallStatusFromInterfaces (line 153) | func FirmwareInstallStatusFromInterfaces(ctx context.Context, installVer...
type FirmwareInstallProvider (line 187) | type FirmwareInstallProvider interface
type firmwareInstallProvider (line 196) | type firmwareInstallProvider struct
function firmwareInstallUploadAndInitiate (line 202) | func firmwareInstallUploadAndInitiate(ctx context.Context, component str...
function FirmwareInstallUploadAndInitiateFromInterfaces (line 231) | func FirmwareInstallUploadAndInitiateFromInterfaces(ctx context.Context,...
type FirmwareInstallerUploaded (line 263) | type FirmwareInstallerUploaded interface
type firmwareInstallerWithOptionsProvider (line 276) | type firmwareInstallerWithOptionsProvider struct
function firmwareInstallUploaded (line 282) | func firmwareInstallUploaded(ctx context.Context, component, uploadTaskI...
function FirmwareInstallerUploadedFromInterfaces (line 313) | func FirmwareInstallerUploadedFromInterfaces(ctx context.Context, compon...
type FirmwareInstallStepsGetter (line 344) | type FirmwareInstallStepsGetter interface
type firmwareInstallStepsGetterProvider (line 349) | type firmwareInstallStepsGetterProvider struct
function FirmwareInstallStepsFromInterfaces (line 355) | func FirmwareInstallStepsFromInterfaces(ctx context.Context, component s...
function firmwareInstallSteps (line 386) | func firmwareInstallSteps(ctx context.Context, component string, generic...
type FirmwareUploader (line 415) | type FirmwareUploader interface
type firmwareUploaderProvider (line 420) | type firmwareUploaderProvider struct
function FirmwareUploadFromInterfaces (line 426) | func FirmwareUploadFromInterfaces(ctx context.Context, component string,...
function firmwareUpload (line 457) | func firmwareUpload(ctx context.Context, component string, file *os.File...
type FirmwareTaskVerifier (line 490) | type FirmwareTaskVerifier interface
type firmwareTaskVerifierProvider (line 506) | type firmwareTaskVerifierProvider struct
function firmwareTaskStatus (line 513) | func firmwareTaskStatus(ctx context.Context, kind bconsts.FirmwareInstal...
function FirmwareTaskStatusFromInterfaces (line 543) | func FirmwareTaskStatusFromInterfaces(ctx context.Context, kind bconsts....
FILE: bmc/firmware_test.go
type firmwareInstallTester (line 17) | type firmwareInstallTester struct
method FirmwareInstall (line 22) | func (f *firmwareInstallTester) FirmwareInstall(ctx context.Context, c...
method Name (line 26) | func (r *firmwareInstallTester) Name() string {
function TestFirmwareInstall (line 30) | func TestFirmwareInstall(t *testing.T) {
function TestFirmwareInstallFromInterfaces (line 71) | func TestFirmwareInstallFromInterfaces(t *testing.T) {
type firmwareInstallStatusTester (line 113) | type firmwareInstallStatusTester struct
method FirmwareInstallStatus (line 118) | func (f *firmwareInstallStatusTester) FirmwareInstallStatus(ctx contex...
method Name (line 122) | func (r *firmwareInstallStatusTester) Name() string {
function TestFirmwareInstallStatus (line 126) | func TestFirmwareInstallStatus(t *testing.T) {
function TestFirmwareInstallStatusFromInterfaces (line 167) | func TestFirmwareInstallStatusFromInterfaces(t *testing.T) {
type firmwareInstallUploadAndInitiateTester (line 208) | type firmwareInstallUploadAndInitiateTester struct
method FirmwareInstallUploadAndInitiate (line 213) | func (f *firmwareInstallUploadAndInitiateTester) FirmwareInstallUpload...
method Name (line 217) | func (r *firmwareInstallUploadAndInitiateTester) Name() string {
function TestFirmwareInstallUploadAndInitiate (line 221) | func TestFirmwareInstallUploadAndInitiate(t *testing.T) {
function TestFirmwareInstallUploadAndInitiateFromInterfaces (line 261) | func TestFirmwareInstallUploadAndInitiateFromInterfaces(t *testing.T) {
type firmwareInstallUploadTester (line 301) | type firmwareInstallUploadTester struct
method FirmwareInstallUploaded (line 306) | func (f *firmwareInstallUploadTester) FirmwareInstallUploaded(ctx cont...
method Name (line 310) | func (r *firmwareInstallUploadTester) Name() string {
function TestFirmwareInstallUploaded (line 314) | func TestFirmwareInstallUploaded(t *testing.T) {
function TestFirmwareInstallerUploadedFromInterfaces (line 355) | func TestFirmwareInstallerUploadedFromInterfaces(t *testing.T) {
type firmwareUploadTester (line 396) | type firmwareUploadTester struct
method FirmwareUpload (line 401) | func (f *firmwareUploadTester) FirmwareUpload(ctx context.Context, com...
method Name (line 405) | func (r *firmwareUploadTester) Name() string {
function TestFirmwareUpload (line 409) | func TestFirmwareUpload(t *testing.T) {
type firmwareInstallStepsGetterTester (line 449) | type firmwareInstallStepsGetterTester struct
method FirmwareInstallSteps (line 454) | func (m *firmwareInstallStepsGetterTester) FirmwareInstallSteps(ctx co...
method Name (line 458) | func (m *firmwareInstallStepsGetterTester) Name() string {
function TestFirmwareInstallStepsFromInterfaces (line 462) | func TestFirmwareInstallStepsFromInterfaces(t *testing.T) {
type firmwareInstallStepsTester (line 502) | type firmwareInstallStepsTester struct
method FirmwareInstallSteps (line 507) | func (f *firmwareInstallStepsTester) FirmwareInstallSteps(ctx context....
method Name (line 511) | func (r *firmwareInstallStepsTester) Name() string {
function TestFirmwareInstallSteps (line 515) | func TestFirmwareInstallSteps(t *testing.T) {
type firmwareTaskStatusTester (line 554) | type firmwareTaskStatusTester struct
method FirmwareTaskStatus (line 560) | func (f *firmwareTaskStatusTester) FirmwareTaskStatus(ctx context.Cont...
method Name (line 564) | func (r *firmwareTaskStatusTester) Name() string {
function TestFirmwareTaskStatus (line 568) | func TestFirmwareTaskStatus(t *testing.T) {
function TestFirmwareTaskStatusFromInterfaces (line 612) | func TestFirmwareTaskStatusFromInterfaces(t *testing.T) {
FILE: bmc/floppy.go
type FloppyImageMounter (line 14) | type FloppyImageMounter interface
type floppyImageUploaderProvider (line 19) | type floppyImageUploaderProvider struct
function mountFloppyImage (line 25) | func mountFloppyImage(ctx context.Context, image io.Reader, p []floppyIm...
function MountFloppyImageFromInterfaces (line 55) | func MountFloppyImageFromInterfaces(ctx context.Context, image io.Reader...
type FloppyImageUnmounter (line 87) | type FloppyImageUnmounter interface
type floppyImageUnmounterProvider (line 92) | type floppyImageUnmounterProvider struct
function unmountFloppyImage (line 98) | func unmountFloppyImage(ctx context.Context, p []floppyImageUnmounterPro...
function UnmountFloppyImageFromInterfaces (line 128) | func UnmountFloppyImageFromInterfaces(ctx context.Context, p []interface...
FILE: bmc/floppy_test.go
type mountFloppyImageTester (line 13) | type mountFloppyImageTester struct
method MountFloppyImage (line 17) | func (p *mountFloppyImageTester) MountFloppyImage(ctx context.Context,...
method Name (line 21) | func (p *mountFloppyImageTester) Name() string {
function TestMountFloppyFromInterfaces (line 25) | func TestMountFloppyFromInterfaces(t *testing.T) {
type unmountFloppyImageTester (line 65) | type unmountFloppyImageTester struct
method UnmountFloppyImage (line 69) | func (p *unmountFloppyImageTester) UnmountFloppyImage(ctx context.Cont...
method Name (line 73) | func (p *unmountFloppyImageTester) Name() string {
function TestUnmountFloppyFromInterfaces (line 77) | func TestUnmountFloppyFromInterfaces(t *testing.T) {
FILE: bmc/inventory.go
type InventoryGetter (line 15) | type InventoryGetter interface
type inventoryGetterProvider (line 19) | type inventoryGetterProvider struct
function inventory (line 25) | func inventory(ctx context.Context, generic []inventoryGetterProvider) (...
function GetInventoryFromInterfaces (line 55) | func GetInventoryFromInterfaces(ctx context.Context, generic []interface...
FILE: bmc/inventory_test.go
type inventoryGetterTester (line 14) | type inventoryGetterTester struct
method Inventory (line 19) | func (f *inventoryGetterTester) Inventory(ctx context.Context) (device...
method Name (line 23) | func (f *inventoryGetterTester) Name() string {
function TestInventory (line 27) | func TestInventory(t *testing.T) {
function TestInventoryFromInterfaces (line 65) | func TestInventoryFromInterfaces(t *testing.T) {
FILE: bmc/nmi.go
type NMISender (line 12) | type NMISender interface
function sendNMI (line 16) | func sendNMI(ctx context.Context, timeout time.Duration, sender NMISende...
function SendNMIFromInterface (line 37) | func SendNMIFromInterface(
FILE: bmc/nmi_test.go
type mockNMISender (line 12) | type mockNMISender struct
method SendNMI (line 16) | func (m *mockNMISender) SendNMI(ctx context.Context) error {
method Name (line 25) | func (m *mockNMISender) Name() string {
function TestSendNMIFromInterface (line 29) | func TestSendNMIFromInterface(t *testing.T) {
FILE: bmc/postcode.go
type PostCodeGetter (line 13) | type PostCodeGetter interface
type postCodeGetterProvider (line 21) | type postCodeGetterProvider struct
function postCode (line 27) | func postCode(ctx context.Context, generic []postCodeGetterProvider) (st...
function GetPostCodeInterfaces (line 57) | func GetPostCodeInterfaces(ctx context.Context, generic []interface{}) (...
FILE: bmc/postcode_test.go
type postCodeGetterTester (line 13) | type postCodeGetterTester struct
method PostCode (line 19) | func (p *postCodeGetterTester) PostCode(ctx context.Context) (status s...
method Name (line 23) | func (p *postCodeGetterTester) Name() string {
function TestPostCode (line 27) | func TestPostCode(t *testing.T) {
function TestPostCodeFromInterfaces (line 67) | func TestPostCodeFromInterfaces(t *testing.T) {
FILE: bmc/power.go
type PowerSetter (line 13) | type PowerSetter interface
type PowerStateGetter (line 29) | type PowerStateGetter interface
type powerProviders (line 34) | type powerProviders struct
function setPowerState (line 41) | func setPowerState(ctx context.Context, timeout time.Duration, state str...
function SetPowerStateFromInterfaces (line 77) | func SetPowerStateFromInterfaces(ctx context.Context, timeout time.Durat...
function getPowerState (line 102) | func getPowerState(ctx context.Context, timeout time.Duration, p []power...
function GetPowerStateFromInterfaces (line 133) | func GetPowerStateFromInterfaces(ctx context.Context, timeout time.Durat...
FILE: bmc/power_test.go
type powerTester (line 13) | type powerTester struct
method PowerSet (line 18) | func (p *powerTester) PowerSet(ctx context.Context, state string) (ok ...
method PowerStateGet (line 28) | func (p *powerTester) PowerStateGet(ctx context.Context) (state string...
method Name (line 35) | func (p *powerTester) Name() string {
function TestSetPowerState (line 39) | func TestSetPowerState(t *testing.T) {
function TestSetPowerStateFromInterfaces (line 79) | func TestSetPowerStateFromInterfaces(t *testing.T) {
function TestGetPowerState (line 128) | func TestGetPowerState(t *testing.T) {
function TestGetPowerStateFromInterfaces (line 165) | func TestGetPowerStateFromInterfaces(t *testing.T) {
FILE: bmc/provider.go
type Provider (line 6) | type Provider interface
function getProviderName (line 13) | func getProviderName(provider interface{}) string {
FILE: bmc/reset.go
type BMCResetter (line 15) | type BMCResetter interface
type bmcProviders (line 20) | type bmcProviders struct
function resetBMC (line 26) | func resetBMC(ctx context.Context, timeout time.Duration, resetType stri...
function ResetBMCFromInterfaces (line 59) | func ResetBMCFromInterfaces(ctx context.Context, timeout time.Duration, ...
FILE: bmc/reset_test.go
type resetTester (line 13) | type resetTester struct
method BmcReset (line 18) | func (r *resetTester) BmcReset(ctx context.Context, resetType string) ...
method Name (line 28) | func (r *resetTester) Name() string {
function TestResetBMC (line 32) | func TestResetBMC(t *testing.T) {
function TestResetBMCFromInterfaces (line 72) | func TestResetBMCFromInterfaces(t *testing.T) {
FILE: bmc/screenshot.go
type ScreenshotGetter (line 13) | type ScreenshotGetter interface
type screenshotGetterProvider (line 17) | type screenshotGetterProvider struct
function screenshot (line 23) | func screenshot(ctx context.Context, generic []screenshotGetterProvider)...
function ScreenshotFromInterfaces (line 52) | func ScreenshotFromInterfaces(ctx context.Context, generic []interface{}...
FILE: bmc/screenshot_test.go
type screenshotTester (line 13) | type screenshotTester struct
method Screenshot (line 17) | func (r *screenshotTester) Screenshot(ctx context.Context) (img []byte...
method Name (line 25) | func (r *screenshotTester) Name() string {
function TestScreenshot (line 29) | func TestScreenshot(t *testing.T) {
function TestScreenshotFromInterfaces (line 71) | func TestScreenshotFromInterfaces(t *testing.T) {
FILE: bmc/sel.go
type SystemEventLog (line 13) | type SystemEventLog interface
type systemEventLogProviders (line 19) | type systemEventLogProviders struct
type SystemEventLogEntries (line 24) | type SystemEventLogEntries
function clearSystemEventLog (line 26) | func clearSystemEventLog(ctx context.Context, timeout time.Duration, s [...
function ClearSystemEventLogFromInterfaces (line 56) | func ClearSystemEventLogFromInterfaces(ctx context.Context, timeout time...
function getSystemEventLog (line 78) | func getSystemEventLog(ctx context.Context, timeout time.Duration, s []s...
function GetSystemEventLogFromInterfaces (line 110) | func GetSystemEventLogFromInterfaces(ctx context.Context, timeout time.D...
function getSystemEventLogRaw (line 132) | func getSystemEventLogRaw(ctx context.Context, timeout time.Duration, s ...
function GetSystemEventLogRawFromInterfaces (line 164) | func GetSystemEventLogRawFromInterfaces(ctx context.Context, timeout tim...
FILE: bmc/sel_test.go
type mockSystemEventLogService (line 12) | type mockSystemEventLogService struct
method ClearSystemEventLog (line 17) | func (m *mockSystemEventLogService) ClearSystemEventLog(ctx context.Co...
method GetSystemEventLog (line 21) | func (m *mockSystemEventLogService) GetSystemEventLog(ctx context.Cont...
method GetSystemEventLogRaw (line 25) | func (m *mockSystemEventLogService) GetSystemEventLogRaw(ctx context.C...
method Name (line 29) | func (m *mockSystemEventLogService) Name() string {
function TestClearSystemEventLog (line 33) | func TestClearSystemEventLog(t *testing.T) {
function TestClearSystemEventLogFromInterfaces (line 50) | func TestClearSystemEventLogFromInterfaces(t *testing.T) {
function TestGetSystemEventLog (line 71) | func TestGetSystemEventLog(t *testing.T) {
function TestGetSystemEventLogFromInterfaces (line 86) | func TestGetSystemEventLogFromInterfaces(t *testing.T) {
function TestGetSystemEventLogRaw (line 104) | func TestGetSystemEventLogRaw(t *testing.T) {
function TestGetSystemEventLogRawFromInterfaces (line 119) | func TestGetSystemEventLogRawFromInterfaces(t *testing.T) {
FILE: bmc/sol.go
type SOLDeactivator (line 13) | type SOLDeactivator interface
type deactivatorProvider (line 18) | type deactivatorProvider struct
function deactivateSOL (line 24) | func deactivateSOL(ctx context.Context, timeout time.Duration, b []deact...
function DeactivateSOLFromInterfaces (line 53) | func DeactivateSOLFromInterfaces(ctx context.Context, timeout time.Durat...
FILE: bmc/sol_test.go
type solTermTester (line 13) | type solTermTester struct
method DeactivateSOL (line 17) | func (r *solTermTester) DeactivateSOL(ctx context.Context) (err error) {
method Name (line 24) | func (r *solTermTester) Name() string {
function TestDeactivateSOL (line 28) | func TestDeactivateSOL(t *testing.T) {
function TestDeactivateSOLFromInterfaces (line 61) | func TestDeactivateSOLFromInterfaces(t *testing.T) {
FILE: bmc/user.go
type UserCreator (line 13) | type UserCreator interface
type UserUpdater (line 18) | type UserUpdater interface
type UserDeleter (line 23) | type UserDeleter interface
type UserReader (line 28) | type UserReader interface
type userProviders (line 33) | type userProviders struct
function createUser (line 42) | func createUser(ctx context.Context, timeout time.Duration, user, pass, ...
function CreateUserFromInterfaces (line 75) | func CreateUserFromInterfaces(ctx context.Context, timeout time.Duration...
function updateUser (line 98) | func updateUser(ctx context.Context, timeout time.Duration, user, pass, ...
function UpdateUserFromInterfaces (line 131) | func UpdateUserFromInterfaces(ctx context.Context, timeout time.Duration...
function deleteUser (line 154) | func deleteUser(ctx context.Context, timeout time.Duration, user string,...
function DeleteUserFromInterfaces (line 187) | func DeleteUserFromInterfaces(ctx context.Context, timeout time.Duration...
function readUsers (line 210) | func readUsers(ctx context.Context, timeout time.Duration, u []userProvi...
function ReadUsersFromInterfaces (line 239) | func ReadUsersFromInterfaces(ctx context.Context, timeout time.Duration,...
FILE: bmc/user_test.go
type userTester (line 13) | type userTester struct
method UserCreate (line 18) | func (p *userTester) UserCreate(ctx context.Context, user, pass, role ...
method UserUpdate (line 28) | func (p *userTester) UserUpdate(ctx context.Context, user, pass, role ...
method UserDelete (line 38) | func (p *userTester) UserDelete(ctx context.Context, user string) (ok ...
method UserRead (line 48) | func (p *userTester) UserRead(ctx context.Context) (users []map[string...
method Name (line 65) | func (p *userTester) Name() string {
function TestUserCreate (line 69) | func TestUserCreate(t *testing.T) {
function TestCreateUserFromInterfaces (line 111) | func TestCreateUserFromInterfaces(t *testing.T) {
function TestUpdateUser (line 163) | func TestUpdateUser(t *testing.T) {
function TestUpdateUserFromInterfaces (line 205) | func TestUpdateUserFromInterfaces(t *testing.T) {
function TestDeleteUser (line 256) | func TestDeleteUser(t *testing.T) {
function TestDeleteUserFromInterfaces (line 296) | func TestDeleteUserFromInterfaces(t *testing.T) {
function TestReadUsers (line 345) | func TestReadUsers(t *testing.T) {
function TestReadUsersFromInterfaces (line 391) | func TestReadUsersFromInterfaces(t *testing.T) {
FILE: bmc/virtual_media.go
type VirtualMediaSetter (line 12) | type VirtualMediaSetter interface
type virtualMediaProviders (line 17) | type virtualMediaProviders struct
function setVirtualMedia (line 23) | func setVirtualMedia(ctx context.Context, kind string, mediaURL string, ...
function SetVirtualMediaFromInterfaces (line 54) | func SetVirtualMediaFromInterfaces(ctx context.Context, kind string, med...
FILE: bmc/virtual_media_test.go
type virtualMediaTester (line 13) | type virtualMediaTester struct
method SetVirtualMedia (line 18) | func (r *virtualMediaTester) SetVirtualMedia(ctx context.Context, kind...
method Name (line 28) | func (r *virtualMediaTester) Name() string {
function TestSetVirtualMedia (line 32) | func TestSetVirtualMedia(t *testing.T) {
function TestSetVirtualMediaFromInterfaces (line 73) | func TestSetVirtualMediaFromInterfaces(t *testing.T) {
FILE: client.go
constant defaultConnectTimeout (line 38) | defaultConnectTimeout = 30 * time.Second
constant pkgName (line 39) | pkgName = "github.com/bmc-toolbox/bmclib"
type Client (line 43) | type Client struct
method defaultTimeout (line 141) | func (c *Client) defaultTimeout(ctx context.Context) time.Duration {
method registerHomeAssistantProvider (line 154) | func (c *Client) registerHomeAssistantProvider() error {
method registerRPCProvider (line 169) | func (c *Client) registerRPCProvider() error {
method registerIPMIProvider (line 184) | func (c *Client) registerIPMIProvider() error {
method registerASRRProvider (line 203) | func (c *Client) registerASRRProvider() {
method registerGofishProvider (line 211) | func (c *Client) registerGofishProvider() {
method registerIntelAMTProvider (line 228) | func (c *Client) registerIntelAMTProvider() {
method registerDellProvider (line 240) | func (c *Client) registerDellProvider() {
method registerSupermicroProvider (line 254) | func (c *Client) registerSupermicroProvider() {
method registerOpenBMCProvider (line 269) | func (c *Client) registerOpenBMCProvider() {
method registerProviders (line 284) | func (c *Client) registerProviders() {
method GetMetadata (line 322) | func (c *Client) GetMetadata() bmc.Metadata {
method setMetadata (line 331) | func (c *Client) setMetadata(metadata bmc.Metadata) {
method registry (line 343) | func (c *Client) registry() *registrar.Registry {
method RegisterSpanAttributes (line 352) | func (c *Client) RegisterSpanAttributes(m bmc.Metadata, span oteltrace...
method Open (line 380) | func (c *Client) Open(ctx context.Context) error {
method Close (line 405) | func (c *Client) Close(ctx context.Context) (err error) {
method FilterForCompatible (line 429) | func (c *Client) FilterForCompatible(ctx context.Context) {
method GetPowerState (line 438) | func (c *Client) GetPowerState(ctx context.Context) (state string, err...
method SetPowerState (line 450) | func (c *Client) SetPowerState(ctx context.Context, state string) (ok ...
method CreateUser (line 462) | func (c *Client) CreateUser(ctx context.Context, user, pass, role stri...
method UpdateUser (line 474) | func (c *Client) UpdateUser(ctx context.Context, user, pass, role stri...
method DeleteUser (line 486) | func (c *Client) DeleteUser(ctx context.Context, user string) (ok bool...
method ReadUsers (line 498) | func (c *Client) ReadUsers(ctx context.Context) (users []map[string]st...
method GetBootDeviceOverride (line 510) | func (c *Client) GetBootDeviceOverride(ctx context.Context) (override ...
method SetBootDevice (line 521) | func (c *Client) SetBootDevice(ctx context.Context, bootDevice string,...
method SetVirtualMedia (line 536) | func (c *Client) SetVirtualMedia(ctx context.Context, kind string, med...
method ResetBMC (line 548) | func (c *Client) ResetBMC(ctx context.Context, resetType string) (ok b...
method DeactivateSOL (line 560) | func (c *Client) DeactivateSOL(ctx context.Context) (err error) {
method Inventory (line 569) | func (c *Client) Inventory(ctx context.Context) (device *common.Device...
method GetBiosConfiguration (line 578) | func (c *Client) GetBiosConfiguration(ctx context.Context) (biosConfig...
method SetBiosConfiguration (line 589) | func (c *Client) SetBiosConfiguration(ctx context.Context, biosConfig ...
method SetBiosConfigurationFromFile (line 600) | func (c *Client) SetBiosConfigurationFromFile(ctx context.Context, cfg...
method ResetBiosConfiguration (line 611) | func (c *Client) ResetBiosConfiguration(ctx context.Context) (err erro...
method FirmwareInstall (line 623) | func (c *Client) FirmwareInstall(ctx context.Context, component string...
method FirmwareInstallStatus (line 637) | func (c *Client) FirmwareInstallStatus(ctx context.Context, installVer...
method PostCode (line 650) | func (c *Client) PostCode(ctx context.Context) (status string, code in...
method Screenshot (line 661) | func (c *Client) Screenshot(ctx context.Context) (image []byte, fileTy...
method ClearSystemEventLog (line 672) | func (c *Client) ClearSystemEventLog(ctx context.Context) (err error) {
method MountFloppyImage (line 683) | func (c *Client) MountFloppyImage(ctx context.Context, image io.Reader...
method UnmountFloppyImage (line 694) | func (c *Client) UnmountFloppyImage(ctx context.Context) (err error) {
method FirmwareInstallSteps (line 706) | func (c *Client) FirmwareInstallSteps(ctx context.Context, component s...
method FirmwareUpload (line 718) | func (c *Client) FirmwareUpload(ctx context.Context, component string,...
method FirmwareTaskStatus (line 730) | func (c *Client) FirmwareTaskStatus(ctx context.Context, kind constant...
method FirmwareInstallUploaded (line 742) | func (c *Client) FirmwareInstallUploaded(ctx context.Context, componen...
method FirmwareInstallUploadAndInitiate (line 753) | func (c *Client) FirmwareInstallUploadAndInitiate(ctx context.Context,...
method GetSystemEventLog (line 765) | func (c *Client) GetSystemEventLog(ctx context.Context) (entries bmc.S...
method GetSystemEventLogRaw (line 775) | func (c *Client) GetSystemEventLogRaw(ctx context.Context) (eventlog s...
method SendNMI (line 785) | func (c *Client) SendNMI(ctx context.Context) error {
type Auth (line 60) | type Auth struct
type providerConfig (line 67) | type providerConfig struct
function NewClient (line 80) | func NewClient(host, user, pass string, opts ...Option) *Client {
FILE: client_test.go
function TestBMC (line 14) | func TestBMC(t *testing.T) {
function TestWithRedfishVersionsNotCompatible (line 57) | func TestWithRedfishVersionsNotCompatible(t *testing.T) {
function TestWithRedfishBasicAuth (line 83) | func TestWithRedfishBasicAuth(t *testing.T) {
function TestWithConnectionTimeout (line 114) | func TestWithConnectionTimeout(t *testing.T) {
function TestDefaultTimeout (line 140) | func TestDefaultTimeout(t *testing.T) {
function equalWithinErrorMargin (line 173) | func equalWithinErrorMargin(a, b time.Duration) bool {
type testProvider (line 177) | type testProvider struct
method Name (line 184) | func (t *testProvider) Name() string {
method Open (line 191) | func (t *testProvider) Open(ctx context.Context) error {
method Close (line 195) | func (t *testProvider) Close(ctx context.Context) error {
method PowerStateGet (line 199) | func (t *testProvider) PowerStateGet(ctx context.Context) (string, err...
method PowerSet (line 203) | func (t *testProvider) PowerSet(ctx context.Context, state string) err...
method BootDeviceSet (line 207) | func (t *testProvider) BootDeviceSet(ctx context.Context, bootDevice s...
function registryNames (line 211) | func registryNames(r []*registrar.Driver) []string {
function TestOpenFiltered (line 219) | func TestOpenFiltered(t *testing.T) {
FILE: constants/constants.go
type OperationApplyTime (line 5) | type OperationApplyTime
type FirmwareInstallStep (line 8) | type FirmwareInstallStep
type TaskState (line 10) | type TaskState
constant EnvEnableDebug (line 16) | EnvEnableDebug = "DEBUG_BMCLIB"
constant HP (line 21) | HP = "HP"
constant Dell (line 23) | Dell = "Dell"
constant Supermicro (line 25) | Supermicro = "Supermicro"
constant Cloudline (line 27) | Cloudline = "Cloudline"
constant Quanta (line 29) | Quanta = "Quanta"
constant Intel (line 31) | Intel = "Intel"
constant Immediate (line 35) | Immediate OperationApplyTime = "Immediate"
constant OnReset (line 37) | OnReset OperationApplyTime = "OnReset"
constant OnStartUpdateRequest (line 39) | OnStartUpdateRequest OperationApplyTime = "OnStartUpdateRequest"
constant FirmwareInstallInitializing (line 51) | FirmwareInstallInitializing = "initializing"
constant Initializing (line 52) | Initializing TaskState = "initializing"
constant FirmwareInstallQueued (line 57) | FirmwareInstallQueued = "queued"
constant Queued (line 58) | Queued TaskState = "queued"
constant FirmwareInstallRunning (line 63) | FirmwareInstallRunning = "running"
constant Running (line 64) | Running TaskState = "running"
constant FirmwareInstallComplete (line 68) | FirmwareInstallComplete = "complete"
constant Complete (line 69) | Complete TaskState = "complete"
constant FirmwareInstallFailed (line 73) | FirmwareInstallFailed = "failed"
constant Failed (line 74) | Failed TaskState = "failed"
constant FirmwareInstallPowerCycleHost (line 77) | FirmwareInstallPowerCycleHost = "powercycle-host"
constant PowerCycleHost (line 78) | PowerCycleHost TaskState = "powercycle-host"
constant FirmwareInstallUnknown (line 80) | FirmwareInstallUnknown = "unknown"
constant Unknown (line 81) | Unknown TaskState = "unknown"
constant FirmwareInstallStepUploadInitiateInstall (line 85) | FirmwareInstallStepUploadInitiateInstall FirmwareInstallStep = "upload-i...
constant FirmwareInstallStepInstallStatus (line 88) | FirmwareInstallStepInstallStatus FirmwareInstallStep = "install-status"
constant FirmwareInstallStepUpload (line 91) | FirmwareInstallStepUpload FirmwareInstallStep = "upload"
constant FirmwareInstallStepUploadStatus (line 94) | FirmwareInstallStepUploadStatus FirmwareInstallStep = "upload-status"
constant FirmwareInstallStepInstallUploaded (line 97) | FirmwareInstallStepInstallUploaded FirmwareInstallStep = "install-uploaded"
constant FirmwareInstallStepPowerOffHost (line 100) | FirmwareInstallStepPowerOffHost FirmwareInstallStep = "power-off-host"
constant FirmwareInstallStepResetBMCPostInstall (line 103) | FirmwareInstallStepResetBMCPostInstall FirmwareInstallStep = "reset-bmc-...
constant FirmwareInstallStepResetBMCOnInstallFailure (line 106) | FirmwareInstallStepResetBMCOnInstallFailure FirmwareInstallStep = "reset...
constant POSTStateBootINIT (line 109) | POSTStateBootINIT = "boot-init/pxe"
constant POSTStateUEFI (line 110) | POSTStateUEFI = "uefi"
constant POSTStateOS (line 111) | POSTStateOS = "grub/os"
constant POSTCodeUnknown (line 112) | POSTCodeUnknown = "unknown"
function ListSupportedVendors (line 116) | func ListSupportedVendors() []string {
FILE: errors/errors.go
type ErrUnsupportedHardware (line 131) | type ErrUnsupportedHardware struct
method Error (line 135) | func (e *ErrUnsupportedHardware) Error() string {
function NewErrUnsupportedHardware (line 139) | func NewErrUnsupportedHardware(s string) error {
FILE: examples/bios/main.go
function main (line 20) | func main() {
FILE: examples/create-users/main.go
function main (line 18) | func main() {
FILE: examples/floppy-image/main.go
function main (line 16) | func main() {
FILE: examples/homeassistant/main.go
function main (line 12) | func main() {
FILE: examples/install-firmware/main.go
function main (line 21) | func main() {
FILE: examples/inventory/main.go
function main (line 19) | func main() {
FILE: examples/reset_bmc/reset_bmc.go
function main (line 14) | func main() {
FILE: examples/rpc/main.go
function main (line 14) | func main() {
function testConsumer (line 68) | func testConsumer(ctx context.Context) error {
FILE: examples/screenshot/main.go
function main (line 18) | func main() {
FILE: examples/sel/main.go
function main (line 16) | func main() {
FILE: examples/status/main.go
function main (line 15) | func main() {
FILE: examples/virtualmedia/main.go
function main (line 15) | func main() {
FILE: filter.go
method PreferProvider (line 9) | func (c *Client) PreferProvider(name string) *Client {
method Supports (line 19) | func (c *Client) Supports(features ...registrar.Feature) *Client {
method Using (line 29) | func (c *Client) Using(protocol string) *Client {
method For (line 39) | func (c *Client) For(provider string) *Client {
method PreferProtocol (line 49) | func (c *Client) PreferProtocol(protocols ...string) *Client {
FILE: internal/executor/errors.go
type ExecError (line 25) | type ExecError struct
method Error (line 33) | func (u *ExecError) Error() string {
function newExecError (line 37) | func newExecError(cmd string, r *Result) *ExecError {
FILE: internal/executor/executor.go
type Executor (line 15) | type Executor interface
function NewExecutor (line 24) | func NewExecutor(cmd string) Executor {
type Execute (line 29) | type Execute struct
method GetCmd (line 46) | func (e *Execute) GetCmd() string {
method SetArgs (line 54) | func (e *Execute) SetArgs(a []string) {
method SetEnv (line 59) | func (e *Execute) SetEnv(env []string) {
method SetStdout (line 64) | func (e *Execute) SetStdout(_ []byte) {
method ExecWithContext (line 68) | func (e *Execute) ExecWithContext(ctx context.Context) (result *Result...
method CheckExecutable (line 100) | func (e *Execute) CheckExecutable() error {
type Result (line 39) | type Result struct
FILE: internal/executor/executor_test.go
function Test_Stdin (line 15) | func Test_Stdin(t *testing.T) {
type checkBinTester (line 29) | type checkBinTester struct
function initCheckBinTests (line 37) | func initCheckBinTests() []checkBinTester {
function Test_CheckExecutable (line 91) | func Test_CheckExecutable(t *testing.T) {
FILE: internal/executor/fake_executor.go
type FakeExecute (line 11) | type FakeExecute struct
method ExecWithContext (line 30) | func (e *FakeExecute) ExecWithContext(_ context.Context) (*Result, err...
method CheckExecutable (line 49) | func (e *FakeExecute) CheckExecutable() error {
method CmdPath (line 55) | func (e *FakeExecute) CmdPath() string {
method SetArgs (line 59) | func (e *FakeExecute) SetArgs(a []string) {
method SetEnv (line 63) | func (e *FakeExecute) SetEnv(env []string) {
method SetQuiet (line 67) | func (e *FakeExecute) SetQuiet() {
method SetVerbose (line 71) | func (e *FakeExecute) SetVerbose() {
method SetStdout (line 75) | func (e *FakeExecute) SetStdout(b []byte) {
method SetStderr (line 79) | func (e *FakeExecute) SetStderr(b []byte) {
method SetStdin (line 83) | func (e *FakeExecute) SetStdin(r io.Reader) {
method DisableBinCheck (line 87) | func (e *FakeExecute) DisableBinCheck() {
method SetExitCode (line 91) | func (e *FakeExecute) SetExitCode(i int) {
method GetCmd (line 95) | func (e *FakeExecute) GetCmd() string {
function NewFakeExecutor (line 23) | func NewFakeExecutor(cmd string) Executor {
FILE: internal/helper/helper.go
function WhosCalling (line 11) | func WhosCalling() string {
FILE: internal/helper/helper_test.go
function TestWhosCalling (line 5) | func TestWhosCalling(t *testing.T) {
FILE: internal/httpclient/httpclient.go
function SecureTLS (line 17) | func SecureTLS(c *http.Client, rootCAs *x509.CertPool) {
function DefaultTransport (line 34) | func DefaultTransport() *http.Transport {
function SecureTLSOption (line 49) | func SecureTLSOption(rootCAs *x509.CertPool) func(*http.Client) {
function Build (line 56) | func Build(opts ...func(*http.Client)) *http.Client {
function StandardizeProcessorName (line 76) | func StandardizeProcessorName(name string) string {
FILE: internal/httpclient/httpclient_test.go
function CertPoolFromCert (line 12) | func CertPoolFromCert(cert *x509.Certificate) *x509.CertPool {
function TestBuildWithOptions (line 18) | func TestBuildWithOptions(t *testing.T) {
FILE: internal/ipmi/ipmi.go
type Ipmi (line 17) | type Ipmi struct
method run (line 74) | func (i *Ipmi) run(ctx context.Context, command []string) (output stri...
method PowerCycle (line 133) | func (i *Ipmi) PowerCycle(ctx context.Context) (status bool, err error) {
method ForceRestart (line 149) | func (i *Ipmi) ForceRestart(ctx context.Context) (status bool, err err...
method PowerReset (line 176) | func (i *Ipmi) PowerReset(ctx context.Context) (status bool, err error) {
method PowerCycleBmc (line 189) | func (i *Ipmi) PowerCycleBmc(ctx context.Context) (status bool, err er...
method PowerResetBmc (line 202) | func (i *Ipmi) PowerResetBmc(ctx context.Context, resetType string) (o...
method PowerOn (line 215) | func (i *Ipmi) PowerOn(ctx context.Context) (status bool, err error) {
method PowerOnForce (line 236) | func (i *Ipmi) PowerOnForce(ctx context.Context) (status bool, err err...
method PowerOff (line 249) | func (i *Ipmi) PowerOff(ctx context.Context) (status bool, err error) {
method PowerSoft (line 261) | func (i *Ipmi) PowerSoft(ctx context.Context) (status bool, err error) {
method PxeOnceEfi (line 275) | func (i *Ipmi) PxeOnceEfi(ctx context.Context) (status bool, err error) {
method BootDeviceSet (line 288) | func (i *Ipmi) BootDeviceSet(ctx context.Context, bootDevice string, s...
method PxeOnceMbr (line 318) | func (i *Ipmi) PxeOnceMbr(ctx context.Context) (status bool, err error) {
method PxeOnce (line 331) | func (i *Ipmi) PxeOnce(ctx context.Context) (status bool, err error) {
method IsOn (line 336) | func (i *Ipmi) IsOn(ctx context.Context) (status bool, err error) {
method PowerState (line 349) | func (i *Ipmi) PowerState(ctx context.Context) (state string, err erro...
method ReadUsers (line 354) | func (i *Ipmi) ReadUsers(ctx context.Context) (users []map[string]stri...
method ClearSystemEventLog (line 385) | func (i *Ipmi) ClearSystemEventLog(ctx context.Context) (err error) {
method GetSystemEventLog (line 391) | func (i *Ipmi) GetSystemEventLog(ctx context.Context) (entries [][]str...
method GetSystemEventLogRaw (line 425) | func (i *Ipmi) GetSystemEventLogRaw(ctx context.Context) (eventlog str...
method DeactivateSOL (line 434) | func (i *Ipmi) DeactivateSOL(ctx context.Context) (err error) {
method SendPowerDiag (line 445) | func (i *Ipmi) SendPowerDiag(ctx context.Context) error {
type Option (line 27) | type Option
function WithIpmitoolPath (line 29) | func WithIpmitoolPath(path string) Option {
function WithCipherSuite (line 35) | func WithCipherSuite(cipherSuite string) Option {
function WithLogger (line 41) | func WithLogger(log logr.Logger) Option {
function New (line 48) | func New(username string, password string, host string, opts ...Option) ...
type cmdOpt (line 110) | type cmdOpt struct
function formatOptions (line 115) | func formatOptions(opts []string) []cmdOpt {
function parseSystemEventLog (line 404) | func parseSystemEventLog(raw string) (entries [][]string) {
FILE: internal/redfishwrapper/bios.go
method GetBiosConfiguration (line 10) | func (c *Client) GetBiosConfiguration(ctx context.Context) (biosConfig m...
method SetBiosConfiguration (line 37) | func (c *Client) SetBiosConfiguration(ctx context.Context, biosConfig ma...
method ResetBiosConfiguration (line 62) | func (c *Client) ResetBiosConfiguration(ctx context.Context) (err error) {
FILE: internal/redfishwrapper/bios_test.go
function biosConfigFromFixture (line 17) | func biosConfigFromFixture(t *testing.T) map[string]string {
function TestGetBiosConfiguration (line 47) | func TestGetBiosConfiguration(t *testing.T) {
FILE: internal/redfishwrapper/boot_device.go
type bootDeviceMapping (line 12) | type bootDeviceMapping struct
function bootDeviceStringToTarget (line 70) | func bootDeviceStringToTarget(device string) (schemas.BootSource, error) {
function bootTargetToBootDeviceType (line 81) | func bootTargetToBootDeviceType(target schemas.BootSource) (bmc.BootDevi...
method SystemBootDeviceSet (line 91) | func (c *Client) SystemBootDeviceSet(_ context.Context, bootDevice strin...
method GetBootDeviceOverride (line 136) | func (c *Client) GetBootDeviceOverride(_ context.Context) (override bmc....
FILE: internal/redfishwrapper/client.go
type Client (line 29) | type Client struct
method Open (line 123) | func (c *Client) Open(ctx context.Context) error {
method Close (line 170) | func (c *Client) Close(ctx context.Context) error {
method SessionActive (line 181) | func (c *Client) SessionActive() error {
method SetHttpClientTimeout (line 200) | func (c *Client) SetHttpClientTimeout(t time.Duration) {
method HttpClientTimeout (line 205) | func (c *Client) HttpClientTimeout() time.Duration {
method RunRawRequestWithHeaders (line 210) | func (c *Client) RunRawRequestWithHeaders(method, url string, payloadB...
method Delete (line 218) | func (c *Client) Delete(url string) (*http.Response, error) {
method Get (line 222) | func (c *Client) Get(url string) (*http.Response, error) {
method VersionCompatible (line 227) | func (c *Client) VersionCompatible() bool {
method GetBootProgress (line 273) | func (c *Client) GetBootProgress() ([]*schemas.BootProgress, error) {
method PostWithHeaders (line 294) | func (c *Client) PostWithHeaders(ctx context.Context, url string, payl...
method PatchWithHeaders (line 298) | func (c *Client) PatchWithHeaders(ctx context.Context, url string, pay...
method Tasks (line 302) | func (c *Client) Tasks(ctx context.Context) ([]*schemas.Task, error) {
method ManagerOdataID (line 311) | func (c *Client) ManagerOdataID(ctx context.Context) (string, error) {
method SystemsBIOSOdataID (line 326) | func (c *Client) SystemsBIOSOdataID(ctx context.Context) (string, erro...
method DeviceVendorModel (line 351) | func (c *Client) DeviceVendorModel(ctx context.Context) (vendor, model...
type Option (line 45) | type Option
function WithHTTPClient (line 48) | func WithHTTPClient(cli *http.Client) Option {
function WithSecureTLS (line 55) | func WithSecureTLS(rootCAs *x509.CertPool) Option {
function WithVersionsNotCompatible (line 65) | func WithVersionsNotCompatible(versions []string) Option {
function WithBasicAuthEnabled (line 72) | func WithBasicAuthEnabled(e bool) Option {
function WithEtagMatchDisabled (line 81) | func WithEtagMatchDisabled(d bool) Option {
function WithLogger (line 88) | func WithLogger(l *logr.Logger) Option {
function WithSystemName (line 94) | func WithSystemName(name string) Option {
function NewClient (line 101) | func NewClient(host, port, user, pass string, opts ...Option) *Client {
function getTimeout (line 160) | func getTimeout(ctx context.Context) time.Duration {
function redfishVersionMeetsOrExceeds (line 243) | func redfishVersionMeetsOrExceeds(version string, major, minor, patch in...
FILE: internal/redfishwrapper/client_test.go
function TestWithVersionsNotCompatible (line 15) | func TestWithVersionsNotCompatible(t *testing.T) {
function TestWithBasicAuthEnabled (line 41) | func TestWithBasicAuthEnabled(t *testing.T) {
function TestWithEtagMatchDisabled (line 67) | func TestWithEtagMatchDisabled(t *testing.T) {
constant fixturesDir (line 94) | fixturesDir = "./fixtures"
function TestManagerOdataID (line 97) | func TestManagerOdataID(t *testing.T) {
function TestSystemsBIOSOdataID (line 161) | func TestSystemsBIOSOdataID(t *testing.T) {
function TestRedfishVersionMeetsOrExceeds (line 224) | func TestRedfishVersionMeetsOrExceeds(t *testing.T) {
function TestGetBootProgress (line 280) | func TestGetBootProgress(t *testing.T) {
FILE: internal/redfishwrapper/firmware.go
type installMethod (line 25) | type installMethod
constant unstructuredHttpPush (line 28) | unstructuredHttpPush installMethod = "unstructuredHttpPush"
constant multipartHttpUpload (line 29) | multipartHttpUpload installMethod = "multipartUpload"
type RedfishUpdateServiceParameters (line 44) | type RedfishUpdateServiceParameters struct
method FirmwareUpload (line 51) | func (c *Client) FirmwareUpload(ctx context.Context, updateFile *os.File...
method StartUpdateForUploadedFirmware (line 130) | func (c *Client) StartUpdateForUploadedFirmware(ctx context.Context) (ta...
type TaskAccepted (line 172) | type TaskAccepted struct
function taskIDFromResponseBody (line 187) | func taskIDFromResponseBody(resp []byte) (taskID string, err error) {
function taskIDFromLocationHeader (line 218) | func taskIDFromLocationHeader(uri string) (taskID string, err error) {
type multipartPayload (line 237) | type multipartPayload struct
method multipartHTTPUpload (line 242) | func (c *Client) multipartHTTPUpload(url string, update *os.File, params...
method unstructuredHttpUpload (line 256) | func (c *Client) unstructuredHttpUpload(url string, update io.Reader) (*...
method firmwareInstallMethodURI (line 270) | func (c *Client) firmwareInstallMethodURI() (method installMethod, updat...
function updateParametersFormField (line 294) | func updateParametersFormField(fieldName string, writer *multipart.Write...
type pipeReaderFakeSeeker (line 311) | type pipeReaderFakeSeeker struct
method Seek (line 316) | func (p pipeReaderFakeSeeker) Seek(offset int64, whence int) (int64, e...
function multipartPayloadSize (line 324) | func multipartPayloadSize(payload *multipartPayload) (int64, *bytes.Buff...
method runRequestWithMultipartPayload (line 380) | func (c *Client) runRequestWithMultipartPayload(url string, payload *mul...
FILE: internal/redfishwrapper/firmware_test.go
function TestRunRequestWithMultipartPayload (line 22) | func TestRunRequestWithMultipartPayload(t *testing.T) {
function TestFirmwareInstallMethodURI (line 130) | func TestFirmwareInstallMethodURI(t *testing.T) {
function TestTaskIDFromResponseBody (line 215) | func TestTaskIDFromResponseBody(t *testing.T) {
function TestTaskIDFromLocationHeader (line 256) | func TestTaskIDFromLocationHeader(t *testing.T) {
function TestUpdateParametersFormField (line 309) | func TestUpdateParametersFormField(t *testing.T) {
function TestMultipartPayloadSize (line 351) | func TestMultipartPayloadSize(t *testing.T) {
FILE: internal/redfishwrapper/inventory.go
method compatibleOdataID (line 56) | func (c *Client) compatibleOdataID(OdataID string, knownOdataIDs []strin...
method Inventory (line 66) | func (c *Client) Inventory(ctx context.Context, failOnError bool) (devic...
method bmcAttributes (line 110) | func (c *Client) bmcAttributes(ctx context.Context, device *common.Devic...
method chassisAttributes (line 160) | func (c *Client) chassisAttributes(ctx context.Context, device *common.D...
method systemAttributes (line 199) | func (c *Client) systemAttributes(device *common.Device, failOnError boo...
method firmwareAttributes (line 250) | func (c *Client) firmwareAttributes(slug, id string, firmwareObj *common...
FILE: internal/redfishwrapper/inventory_collect.go
method collectEnclosure (line 15) | func (c *Client) collectEnclosure(ch *schemas.Chassis, device *common.De...
method collectPSUs (line 46) | func (c *Client) collectPSUs(ch *schemas.Chassis, device *common.Device,...
method collectTPMs (line 87) | func (c *Client) collectTPMs(sys *schemas.ComputerSystem, device *common...
method collectNICs (line 113) | func (c *Client) collectNICs(sys *schemas.ComputerSystem, device *common...
method collectNetworkPortInfo (line 191) | func (c *Client) collectNetworkPortInfo(
method collectEthernetInfo (line 240) | func (c *Client) collectEthernetInfo(nicPort *common.NICPort, ethernetIn...
function getFirmwareVersionFromController (line 282) | func getFirmwareVersionFromController(controllers []schemas.Controllers,...
method collectBIOS (line 291) | func (c *Client) collectBIOS(sys *schemas.ComputerSystem, device *common...
method collectDrives (line 316) | func (c *Client) collectDrives(sys *schemas.ComputerSystem, device *comm...
method collectStorageControllers (line 372) | func (c *Client) collectStorageControllers(sys *schemas.ComputerSystem, ...
method collectCPUs (line 416) | func (c *Client) collectCPUs(sys *schemas.ComputerSystem, device *common...
method collectDIMMs (line 455) | func (c *Client) collectDIMMs(sys *schemas.ComputerSystem, device *commo...
method collectCPLDs (line 487) | func (c *Client) collectCPLDs(device *common.Device, softwareInventory [...
FILE: internal/redfishwrapper/inventory_collect_test.go
function TestInventoryCollectNetworkPortInfo (line 12) | func TestInventoryCollectNetworkPortInfo(t *testing.T) {
function TestInventoryCollectEthernetInfo (line 115) | func TestInventoryCollectEthernetInfo(t *testing.T) {
FILE: internal/redfishwrapper/main_test.go
function mustReadFile (line 11) | func mustReadFile(t *testing.T, filename string) []byte {
FILE: internal/redfishwrapper/power.go
method PowerSet (line 15) | func (c *Client) PowerSet(ctx context.Context, state string) (ok bool, e...
method BMCReset (line 34) | func (c *Client) BMCReset(ctx context.Context, resetType string) (ok boo...
method SystemPowerOn (line 52) | func (c *Client) SystemPowerOn(ctx context.Context) (ok bool, err error) {
method SystemPowerOff (line 75) | func (c *Client) SystemPowerOff(ctx context.Context) (ok bool, err error) {
method SystemReset (line 99) | func (c *Client) SystemReset(ctx context.Context) (ok bool, err error) {
method SystemPowerCycle (line 128) | func (c *Client) SystemPowerCycle(ctx context.Context) (ok bool, err err...
method SystemPowerStatus (line 152) | func (c *Client) SystemPowerStatus(ctx context.Context) (result string, ...
method SystemForceOff (line 166) | func (c *Client) SystemForceOff(ctx context.Context) (ok bool, err error) {
method SendNMI (line 190) | func (c *Client) SendNMI(_ context.Context) error {
FILE: internal/redfishwrapper/sel.go
method ClearSystemEventLog (line 13) | func (c *Client) ClearSystemEventLog(ctx context.Context) (err error) {
method GetSystemEventLog (line 41) | func (c *Client) GetSystemEventLog(ctx context.Context) (entries [][]str...
method GetSystemEventLogRaw (line 78) | func (c *Client) GetSystemEventLogRaw(ctx context.Context) (eventlog str...
FILE: internal/redfishwrapper/system.go
method AccountService (line 16) | func (c *Client) AccountService() (*schemas.AccountService, error) {
method UpdateService (line 25) | func (c *Client) UpdateService() (*schemas.UpdateService, error) {
method System (line 35) | func (c *Client) System() (*schemas.ComputerSystem, error) {
method Manager (line 59) | func (c *Client) Manager(ctx context.Context) (*schemas.Manager, error) {
method Managers (line 89) | func (c *Client) Managers(ctx context.Context) ([]*schemas.Manager, erro...
method Chassis (line 98) | func (c *Client) Chassis(ctx context.Context) ([]*schemas.Chassis, error) {
method matchingSystem (line 106) | func (c *Client) matchingSystem(systems []*schemas.ComputerSystem) (*sch...
FILE: internal/redfishwrapper/system_test.go
function TestMatchingSystem (line 10) | func TestMatchingSystem(t *testing.T) {
FILE: internal/redfishwrapper/task.go
method Task (line 18) | func (c *Client) Task(ctx context.Context, taskID string) (*schemas.Task...
method TaskStatus (line 35) | func (c *Client) TaskStatus(ctx context.Context, taskID string) (constan...
method taskMessagesAsString (line 57) | func (c *Client) taskMessagesAsString(messages []schemas.Message) string {
method ConvertTaskState (line 74) | func (c *Client) ConvertTaskState(state string) constants.TaskState {
method TaskStateActive (line 93) | func (c *Client) TaskStateActive(state constants.TaskState) (bool, error) {
FILE: internal/redfishwrapper/task_test.go
function TestConvertTaskState (line 15) | func TestConvertTaskState(t *testing.T) {
function TestTaskStateActive (line 50) | func TestTaskStateActive(t *testing.T) {
function TestTaskStatus (line 85) | func TestTaskStatus(t *testing.T) {
function TestTask (line 221) | func TestTask(t *testing.T) {
FILE: internal/redfishwrapper/virtual_media.go
method getVirtualMedia (line 20) | func (c *Client) getVirtualMedia(ctx context.Context) ([]*schemas.Virtua...
method SetVirtualMedia (line 46) | func (c *Client) SetVirtualMedia(ctx context.Context, kind string, media...
method InsertedVirtualMedia (line 129) | func (c *Client) InsertedVirtualMedia(ctx context.Context) ([]string, er...
FILE: internal/redfishwrapper/virtual_media_test.go
function TestGetVirtualMedia (line 14) | func TestGetVirtualMedia(t *testing.T) {
function TestSetVirtualMedia_DellSystemPath (line 108) | func TestSetVirtualMedia_DellSystemPath(t *testing.T) {
function TestInsertedVirtualMedia_DellSystemPath (line 145) | func TestInsertedVirtualMedia_DellSystemPath(t *testing.T) {
function TestSetVirtualMedia_SlotFallback (line 179) | func TestSetVirtualMedia_SlotFallback(t *testing.T) {
function TestSetVirtualMedia_InvalidMediaType (line 222) | func TestSetVirtualMedia_InvalidMediaType(t *testing.T) {
FILE: internal/sum/sum.go
type Sum (line 20) | type Sum struct
method Open (line 77) | func (c *Sum) Open(ctx context.Context) (err error) {
method Close (line 82) | func (c *Sum) Close(ctx context.Context) (err error) {
method run (line 86) | func (s *Sum) run(ctx context.Context, command string, additionalArgs ...
method GetCurrentBiosCfg (line 106) | func (s *Sum) GetCurrentBiosCfg(ctx context.Context) (output string, e...
method LoadDefaultBiosCfg (line 110) | func (s *Sum) LoadDefaultBiosCfg(ctx context.Context) (err error) {
method ChangeBiosCfg (line 115) | func (s *Sum) ChangeBiosCfg(ctx context.Context, cfgFile string, reboo...
method GetBiosConfiguration (line 128) | func (s *Sum) GetBiosConfiguration(ctx context.Context) (biosConfig ma...
method SetBiosConfiguration (line 154) | func (s *Sum) SetBiosConfiguration(ctx context.Context, biosConfig map...
method SetBiosConfigurationFromFile (line 237) | func (s *Sum) SetBiosConfigurationFromFile(ctx context.Context, cfg st...
method ResetBiosConfiguration (line 260) | func (s *Sum) ResetBiosConfiguration(ctx context.Context) (err error) {
type Option (line 30) | type Option
function WithSumPath (line 32) | func WithSumPath(sumPath string) Option {
function WithLogger (line 38) | func WithLogger(log logr.Logger) Option {
function New (line 44) | func New(host, user, pass string, opts ...Option) (*Sum, error) {
FILE: internal/sum/sum_test.go
function newFakeSum (line 11) | func newFakeSum(t *testing.T, fixtureName string) *Sum {
function TestExec_Run (line 26) | func TestExec_Run(t *testing.T) {
function TestExec_SetBiosConfiguration (line 42) | func TestExec_SetBiosConfiguration(t *testing.T) {
function TestExec_GetBiosConfiguration (line 71) | func TestExec_GetBiosConfiguration(t *testing.T) {
FILE: internal/utils.go
function IsntLetterOrNumber (line 8) | func IsntLetterOrNumber(c rune) bool {
function IsRoleValid (line 12) | func IsRoleValid(role string) bool {
function StringInSlice (line 16) | func StringInSlice(str string, sl []string) bool {
FILE: logging/logging.go
function DefaultLogger (line 14) | func DefaultLogger() logr.Logger {
function ZeroLogger (line 34) | func ZeroLogger(level string) logr.Logger {
FILE: option.go
type Option (line 18) | type Option
function WithLogger (line 21) | func WithLogger(logger logr.Logger) Option {
function WithRegistry (line 26) | func WithRegistry(registry *registrar.Registry) Option {
function WithSecureTLS (line 32) | func WithSecureTLS(rootCAs *x509.CertPool) Option {
function WithHTTPClient (line 39) | func WithHTTPClient(c *http.Client) Option {
function WithPerProviderTimeout (line 52) | func WithPerProviderTimeout(timeout time.Duration) Option {
function WithIpmitoolCipherSuite (line 58) | func WithIpmitoolCipherSuite(cipherSuite string) Option {
function WithIpmitoolPort (line 64) | func WithIpmitoolPort(port string) Option {
function WithIpmitoolPath (line 70) | func WithIpmitoolPath(path string) Option {
function WithAsrockrackHTTPClient (line 76) | func WithAsrockrackHTTPClient(httpClient *http.Client) Option {
function WithAsrockrackPort (line 82) | func WithAsrockrackPort(port string) Option {
function WithRedfishHTTPClient (line 88) | func WithRedfishHTTPClient(httpClient *http.Client) Option {
function WithRedfishPort (line 94) | func WithRedfishPort(port string) Option {
function WithRedfishVersionsNotCompatible (line 104) | func WithRedfishVersionsNotCompatible(versions []string) Option {
function WithRedfishUseBasicAuth (line 110) | func WithRedfishUseBasicAuth(useBasicAuth bool) Option {
function WithRedfishEtagMatchDisabled (line 116) | func WithRedfishEtagMatchDisabled(d bool) Option {
function WithRedfishSystemName (line 122) | func WithRedfishSystemName(name string) Option {
function WithIntelAMTHostScheme (line 128) | func WithIntelAMTHostScheme(hostScheme string) Option {
function WithIntelAMTPort (line 134) | func WithIntelAMTPort(port uint32) Option {
function WithDellRedfishVersionsNotCompatible (line 144) | func WithDellRedfishVersionsNotCompatible(versions []string) Option {
function WithDellRedfishUseBasicAuth (line 150) | func WithDellRedfishUseBasicAuth(useBasicAuth bool) Option {
function WithRPCOpt (line 156) | func WithRPCOpt(opt rpc.Provider) Option {
function WithHomeAssistantOpt (line 162) | func WithHomeAssistantOpt(opt homeassistant.Config) Option {
function WithTracerProvider (line 170) | func WithTracerProvider(provider oteltrace.TracerProvider) Option {
FILE: providers/asrockrack/asrockrack.go
constant ProviderName (line 21) | ProviderName = "asrockrack"
constant ProviderProtocol (line 23) | ProviderProtocol = "vendorapi"
constant E3C256D4ID_NL (line 25) | E3C256D4ID_NL = "E3C256D4ID-NL"
constant E3C246D4ID_NL (line 26) | E3C246D4ID_NL = "E3C246D4ID-NL"
constant E3C246D4I_NL (line 27) | E3C246D4I_NL = "E3C246D4I-NL"
type ASRockRack (line 48) | type ASRockRack struct
method Name (line 111) | func (a *ASRockRack) Name() string {
method Open (line 116) | func (a *ASRockRack) Open(ctx context.Context) (err error) {
method supported (line 124) | func (a *ASRockRack) supported(ctx context.Context) error {
method Close (line 157) | func (a *ASRockRack) Close(ctx context.Context) (err error) {
method CheckCredentials (line 166) | func (a *ASRockRack) CheckCredentials(ctx context.Context) (err error) {
method PostCode (line 170) | func (a *ASRockRack) PostCode(ctx context.Context) (status string, cod...
type Config (line 61) | type Config struct
type ASRockOption (line 67) | type ASRockOption
function WithSecureTLS (line 71) | func WithSecureTLS(rootCAs *x509.CertPool) ASRockOption {
function WithHTTPClient (line 78) | func WithHTTPClient(c *http.Client) ASRockOption {
function New (line 85) | func New(ip string, username string, password string, log logr.Logger) *...
function NewWithOptions (line 90) | func NewWithOptions(ip string, username string, password string, log log...
FILE: providers/asrockrack/asrockrack_test.go
function TestHttpLogin (line 12) | func TestHttpLogin(t *testing.T) {
function TestClose (line 21) | func TestClose(t *testing.T) {
function TestFirwmwareUpdateBMC (line 33) | func TestFirwmwareUpdateBMC(t *testing.T) {
FILE: providers/asrockrack/firmware.go
constant versionStrError (line 19) | versionStrError = -1
constant versionStrMatch (line 20) | versionStrMatch = 0
constant versionStrMismatch (line 21) | versionStrMismatch = 1
constant versionStrEmpty (line 22) | versionStrEmpty = 2
method FirmwareInstallSteps (line 26) | func (a *ASRockRack) FirmwareInstallSteps(ctx context.Context, component...
method FirmwareUpload (line 45) | func (a *ASRockRack) FirmwareUpload(ctx context.Context, component strin...
method firmwareUploadBMC (line 57) | func (a *ASRockRack) firmwareUploadBMC(ctx context.Context, file *os.Fil...
method firmwareUploadBIOS (line 104) | func (a *ASRockRack) firmwareUploadBIOS(ctx context.Context, file *os.Fi...
method FirmwareInstallUploaded (line 136) | func (a *ASRockRack) FirmwareInstallUploaded(ctx context.Context, compon...
method firmwareInstallUploadedBIOS (line 148) | func (a *ASRockRack) firmwareInstallUploadedBIOS(ctx context.Context) er...
method firmwareInstallUploadedBMC (line 163) | func (a *ASRockRack) firmwareInstallUploadedBMC(ctx context.Context) err...
method FirmwareTaskStatus (line 178) | func (a *ASRockRack) FirmwareTaskStatus(ctx context.Context, kind consta...
method firmwareUpdateStatus (line 189) | func (a *ASRockRack) firmwareUpdateStatus(ctx context.Context, component...
method versionInstalled (line 258) | func (a *ASRockRack) versionInstalled(ctx context.Context, component, ve...
FILE: providers/asrockrack/helpers.go
type loginSession (line 20) | type loginSession struct
type firmwareInfo (line 28) | type firmwareInfo struct
type biosPOSTCode (line 39) | type biosPOSTCode struct
type component (line 45) | type component struct
type fru (line 59) | type fru struct
type sensor (line 76) | type sensor struct
type preserveConfig (line 100) | type preserveConfig struct
type upgradeProgress (line 110) | type upgradeProgress struct
type chassisStatus (line 118) | type chassisStatus struct
type biosUpdateAction (line 126) | type biosUpdateAction struct
method listUsers (line 140) | func (a *ASRockRack) listUsers(ctx context.Context) ([]*UserAccount, err...
method createUpdateUser (line 160) | func (a *ASRockRack) createUpdateUser(ctx context.Context, account *User...
method setFlashMode (line 186) | func (a *ASRockRack) setFlashMode(ctx context.Context) error {
function multipartSize (line 218) | func multipartSize(fieldname, filename string) int64 {
method uploadFirmware (line 227) | func (a *ASRockRack) uploadFirmware(ctx context.Context, endpoint string...
method verifyUploadedFirmware (line 290) | func (a *ASRockRack) verifyUploadedFirmware(ctx context.Context) error {
method upgradeBMC (line 304) | func (a *ASRockRack) upgradeBMC(ctx context.Context) error {
method flashProgress (line 328) | func (a *ASRockRack) flashProgress(ctx context.Context, endpoint string)...
method firmwareInfo (line 348) | func (a *ASRockRack) firmwareInfo(ctx context.Context) (*firmwareInfo, e...
method postCodeInfo (line 368) | func (a *ASRockRack) postCodeInfo(ctx context.Context) (*biosPOSTCode, e...
method inventoryInfoE3C246D41D (line 388) | func (a *ASRockRack) inventoryInfoE3C246D41D(ctx context.Context) ([]*co...
method fruInfo (line 408) | func (a *ASRockRack) fruInfo(ctx context.Context) ([]*fru, error) {
method sensors (line 454) | func (a *ASRockRack) sensors(ctx context.Context) ([]*sensor, error) {
method biosUpgradeConfiguration (line 475) | func (a *ASRockRack) biosUpgradeConfiguration(ctx context.Context) error {
method upgradeBIOS (line 500) | func (a *ASRockRack) upgradeBIOS(ctx context.Context) error {
method chassisStatusInfo (line 525) | func (a *ASRockRack) chassisStatusInfo(ctx context.Context) (*chassisSta...
method httpsLogin (line 545) | func (a *ASRockRack) httpsLogin(ctx context.Context) error {
method httpsLogout (line 577) | func (a *ASRockRack) httpsLogout(ctx context.Context) error {
method queryHTTPS (line 593) | func (a *ASRockRack) queryHTTPS(ctx context.Context, endpoint, method st...
FILE: providers/asrockrack/helpers_test.go
function Test_FirmwareInfo (line 10) | func Test_FirmwareInfo(t *testing.T) {
function TestInventoryInfo (line 35) | func TestInventoryInfo(t *testing.T) {
function Test_fruInfo (line 50) | func Test_fruInfo(t *testing.T) {
function Test_sensors (line 64) | func Test_sensors(t *testing.T) {
function Test_biosPOSTCode (line 78) | func Test_biosPOSTCode(t *testing.T) {
function Test_chassisStatus (line 97) | func Test_chassisStatus(t *testing.T) {
FILE: providers/asrockrack/inventory.go
method Inventory (line 10) | func (a *ASRockRack) Inventory(ctx context.Context) (device *common.Devi...
method systemHealth (line 43) | func (a *ASRockRack) systemHealth(ctx context.Context, device *common.De...
method fruAttributes (line 79) | func (a *ASRockRack) fruAttributes(ctx context.Context, device *common.D...
method systemAttributes (line 111) | func (a *ASRockRack) systemAttributes(ctx context.Context, device *commo...
method componentAttributesE3C246 (line 153) | func (a *ASRockRack) componentAttributesE3C246(ctx context.Context, fwIn...
FILE: providers/asrockrack/inventory_test.go
function TestGetInventory (line 10) | func TestGetInventory(t *testing.T) {
FILE: providers/asrockrack/mock_test.go
type testFwUpgradeState (line 42) | type testFwUpgradeState struct
function TestMain (line 54) | func TestMain(m *testing.M) {
function mockASRockBMC (line 71) | func mockASRockBMC() *httptest.Server {
function index (line 98) | func index(w http.ResponseWriter, r *http.Request) {
function userAccountList (line 105) | func userAccountList(w http.ResponseWriter, r *http.Request) {
function biosFirmwareUpgrade (line 118) | func biosFirmwareUpgrade(w http.ResponseWriter, r *http.Request) {
function bmcFirmwareUpgrade (line 138) | func bmcFirmwareUpgrade(w http.ResponseWriter, r *http.Request) {
function fwinfo (line 241) | func fwinfo(w http.ResponseWriter, r *http.Request) {
function fruinfo (line 248) | func fruinfo(w http.ResponseWriter, r *http.Request) {
function inventoryinfo (line 255) | func inventoryinfo(w http.ResponseWriter, r *http.Request) {
function sensorsinfo (line 262) | func sensorsinfo(w http.ResponseWriter, r *http.Request) {
function biosPOSTCodeinfo (line 278) | func biosPOSTCodeinfo(w http.ResponseWriter, r *http.Request) {
function chassisStatusInfo (line 285) | func chassisStatusInfo(w http.ResponseWriter, r *http.Request) {
function session (line 292) | func session(w http.ResponseWriter, r *http.Request) {
FILE: providers/asrockrack/power.go
type power (line 15) | type power struct
method PowerStateGet (line 20) | func (a *ASRockRack) PowerStateGet(ctx context.Context) (state string, e...
method PowerSet (line 64) | func (a *ASRockRack) PowerSet(ctx context.Context, state string) (ok boo...
method powerAction (line 81) | func (a *ASRockRack) powerAction(ctx context.Context, action int) (ok bo...
method BmcReset (line 114) | func (a *ASRockRack) BmcReset(ctx context.Context, resetType string) (ok...
method resetBMC (line 124) | func (a *ASRockRack) resetBMC(ctx context.Context) error {
FILE: providers/asrockrack/user.go
type UserAccount (line 20) | type UserAccount struct
method UserRead (line 49) | func (a *ASRockRack) UserRead(ctx context.Context) (users []map[string]s...
method UserCreate (line 76) | func (a *ASRockRack) UserCreate(ctx context.Context, user, pass, role st...
method UserUpdate (line 119) | func (a *ASRockRack) UserUpdate(ctx context.Context, user, pass, role st...
function newUserAccount (line 166) | func newUserAccount(id int, user, pass, role string) *UserAccount {
FILE: providers/asrockrack/user_test.go
type testCase (line 17) | type testCase struct
function Test_UserRead (line 49) | func Test_UserRead(t *testing.T) {
function Test_UserCreate (line 89) | func Test_UserCreate(t *testing.T) {
function Test_UserUpdate (line 124) | func Test_UserUpdate(t *testing.T) {
function Test_createUser (line 159) | func Test_createUser(t *testing.T) {
function Test_userAccounts (line 202) | func Test_userAccounts(t *testing.T) {
FILE: providers/dell/firmware.go
method FirmwareInstallSteps (line 21) | func (c *Conn) FirmwareInstallSteps(ctx context.Context, component strin...
method FirmwareInstallUploadAndInitiate (line 32) | func (c *Conn) FirmwareInstallUploadAndInitiate(ctx context.Context, com...
method checkQueueability (line 64) | func (c *Conn) checkQueueability(component string, tasks []*schemas.Task...
method FirmwareTaskStatus (line 99) | func (c *Conn) FirmwareTaskStatus(ctx context.Context, kind constants.Fi...
method statusFromJob (line 119) | func (c *Conn) statusFromJob(taskID string) (constants.TaskState, string...
method statusFromTaskOem (line 139) | func (c *Conn) statusFromTaskOem(taskID string, oem json.RawMessage) (co...
method job (line 159) | func (c *Conn) job(jobID string) (*Dell, error) {
type oem (line 188) | type oem struct
type Dell (line 192) | type Dell struct
function convFirmwareTaskOem (line 209) | func convFirmwareTaskOem(oemdata json.RawMessage) (oem, error) {
FILE: providers/dell/firmware_test.go
function TestConvFirmwareTaskOem (line 9) | func TestConvFirmwareTaskOem(t *testing.T) {
FILE: providers/dell/idrac.go
constant ProviderName (line 26) | ProviderName = "dell"
constant ProviderProtocol (line 28) | ProviderProtocol = "redfish"
constant redfishV1Prefix (line 30) | redfishV1Prefix = "/redfish/v1"
constant screenshotEndpoint (line 31) | screenshotEndpoint = "/Dell/Managers/iDRAC.Embedded.1/DellLCServi...
constant managerAttributesEndpoint (line 32) | managerAttributesEndpoint = "/Managers/iDRAC.Embedded.1/Attributes"
type Config (line 54) | type Config struct
type Option (line 63) | type Option
function WithHttpClient (line 65) | func WithHttpClient(httpClient *http.Client) Option {
function WithPort (line 71) | func WithPort(port string) Option {
function WithVersionsNotCompatible (line 77) | func WithVersionsNotCompatible(versionsNotCompatible []string) Option {
function WithRootCAs (line 83) | func WithRootCAs(rootCAs *x509.CertPool) Option {
function WithUseBasicAuth (line 89) | func WithUseBasicAuth(useBasicAuth bool) Option {
type Conn (line 96) | type Conn struct
method Open (line 130) | func (c *Conn) Open(ctx context.Context) (err error) {
method deviceSupported (line 148) | func (c *Conn) deviceSupported(ctx context.Context) error {
method Close (line 163) | func (c *Conn) Close(ctx context.Context) error {
method Name (line 168) | func (c *Conn) Name() string {
method Compatible (line 173) | func (c *Conn) Compatible(ctx context.Context) bool {
method PowerStateGet (line 206) | func (c *Conn) PowerStateGet(ctx context.Context) (state string, err e...
method PowerSet (line 211) | func (c *Conn) PowerSet(ctx context.Context, state string) (ok bool, e...
method Inventory (line 216) | func (c *Conn) Inventory(ctx context.Context) (device *common.Device, ...
method BmcReset (line 221) | func (c *Conn) BmcReset(ctx context.Context, resetType string) (ok boo...
method GetBiosConfiguration (line 226) | func (c *Conn) GetBiosConfiguration(ctx context.Context) (biosConfig m...
method SetBiosConfiguration (line 231) | func (c *Conn) SetBiosConfiguration(ctx context.Context, biosConfig ma...
method ResetBiosConfiguration (line 236) | func (c *Conn) ResetBiosConfiguration(ctx context.Context) (err error) {
method SendNMI (line 241) | func (c *Conn) SendNMI(ctx context.Context) error {
method deviceManufacturer (line 246) | func (c *Conn) deviceManufacturer(ctx context.Context) (vendor string,...
method Screenshot (line 259) | func (c *Conn) Screenshot(ctx context.Context) (image []byte, fileType...
function New (line 102) | func New(host, user, pass string, log logr.Logger, opts ...Option) *Conn {
FILE: providers/dell/idrac_test.go
constant fixturesDir (line 22) | fixturesDir = "./fixtures"
function Test_Screenshot (line 49) | func Test_Screenshot(t *testing.T) {
function TestOpenErrors (line 125) | func TestOpenErrors(t *testing.T) {
FILE: providers/homeassistant/homeassistant.go
constant ProviderName (line 21) | ProviderName = "homeassistant"
constant ProviderProtocol (line 23) | ProviderProtocol = "http"
type Config (line 33) | type Config struct
method Name (line 60) | func (p *Config) Name() string {
method Open (line 65) | func (p *Config) Open(ctx context.Context) error {
method haGetEntityState (line 78) | func (p *Config) haGetEntityState(ctx context.Context, haEntityId stri...
method Close (line 133) | func (p *Config) Close(_ context.Context) (err error) {
method PowerStateGet (line 138) | func (p *Config) PowerStateGet(ctx context.Context) (state string, err...
method PowerSet (line 148) | func (p *Config) PowerSet(ctx context.Context, state string) (ok bool,...
method BootDeviceSet (line 210) | func (p *Config) BootDeviceSet(ctx context.Context, bootDevice string,...
type EntityStateResponse (line 42) | type EntityStateResponse struct
function New (line 49) | func New(apiUrl string, apiToken string) *Config {
FILE: providers/intelamt/intelamt.go
constant ProviderName (line 16) | ProviderName = "IntelAMT"
constant ProviderProtocol (line 18) | ProviderProtocol = "AMT"
type iamtClient (line 31) | type iamtClient interface
type Conn (line 42) | type Conn struct
method Name (line 97) | func (c *Conn) Name() string {
method Open (line 102) | func (c *Conn) Open(ctx context.Context) (err error) {
method Close (line 107) | func (c *Conn) Close(ctx context.Context) (err error) {
method Compatible (line 112) | func (c *Conn) Compatible(ctx context.Context) bool {
method BootDeviceSet (line 125) | func (c *Conn) BootDeviceSet(ctx context.Context, bootDevice string, s...
method PowerStateGet (line 137) | func (c *Conn) PowerStateGet(ctx context.Context) (state string, err e...
method PowerSet (line 150) | func (c *Conn) PowerSet(ctx context.Context, state string) (ok bool, e...
type Option (line 47) | type Option
function WithPort (line 49) | func WithPort(port uint32) Option {
function WithHostScheme (line 55) | func WithHostScheme(hostScheme string) Option {
function WithLogger (line 61) | func WithLogger(logger logr.Logger) Option {
type Config (line 67) | type Config struct
function New (line 76) | func New(host string, user string, pass string, opts ...Option) *Conn {
FILE: providers/intelamt/intelamt_test.go
type mock (line 13) | type mock struct
method Open (line 23) | func (m *mock) Open(ctx context.Context) error {
method Close (line 27) | func (m *mock) Close(ctx context.Context) error {
method IsPoweredOn (line 31) | func (m *mock) IsPoweredOn(ctx context.Context) (bool, error) {
method PowerOn (line 38) | func (m *mock) PowerOn(ctx context.Context) error {
method PowerOff (line 42) | func (m *mock) PowerOff(ctx context.Context) error {
method PowerCycle (line 46) | func (m *mock) PowerCycle(ctx context.Context) error {
method SetPXE (line 50) | func (m *mock) SetPXE(ctx context.Context) error {
function TestClose (line 54) | func TestClose(t *testing.T) {
function TestName (line 61) | func TestName(t *testing.T) {
function TestBootDeviceSet (line 68) | func TestBootDeviceSet(t *testing.T) {
function TestPowerStateGet (line 103) | func TestPowerStateGet(t *testing.T) {
function TestPowerSet (line 142) | func TestPowerSet(t *testing.T) {
function TestCompatible (line 194) | func TestCompatible(t *testing.T) {
function TestNew (line 225) | func TestNew(t *testing.T) {
FILE: providers/ipmitool/ipmitool.go
constant ProviderName (line 17) | ProviderName = "ipmitool"
constant ProviderProtocol (line 19) | ProviderProtocol = "ipmi"
type Conn (line 38) | type Conn struct
method Open (line 101) | func (c *Conn) Open(ctx context.Context) (err error) {
method Close (line 111) | func (c *Conn) Close(ctx context.Context) (err error) {
method Compatible (line 116) | func (c *Conn) Compatible(ctx context.Context) bool {
method Name (line 139) | func (c *Conn) Name() string {
method BootDeviceSet (line 144) | func (c *Conn) BootDeviceSet(ctx context.Context, bootDevice string, s...
method BmcReset (line 149) | func (c *Conn) BmcReset(ctx context.Context, resetType string) (ok boo...
method DeactivateSOL (line 154) | func (c *Conn) DeactivateSOL(ctx context.Context) (err error) {
method UserRead (line 159) | func (c *Conn) UserRead(ctx context.Context) (users []map[string]strin...
method PowerStateGet (line 164) | func (c *Conn) PowerStateGet(ctx context.Context) (state string, err e...
method PowerSet (line 169) | func (c *Conn) PowerSet(ctx context.Context, state string) (ok bool, e...
method ClearSystemEventLog (line 193) | func (c *Conn) ClearSystemEventLog(ctx context.Context) (err error) {
method GetSystemEventLog (line 197) | func (c *Conn) GetSystemEventLog(ctx context.Context) (entries [][]str...
method GetSystemEventLogRaw (line 201) | func (c *Conn) GetSystemEventLogRaw(ctx context.Context) (eventlog str...
method SendNMI (line 206) | func (c *Conn) SendNMI(ctx context.Context) error {
type Config (line 43) | type Config struct
type Option (line 51) | type Option
function WithLogger (line 53) | func WithLogger(log logr.Logger) Option {
function WithPort (line 59) | func WithPort(port string) Option {
function WithCipherSuite (line 65) | func WithCipherSuite(cipherSuite string) Option {
function WithIpmitoolPath (line 71) | func WithIpmitoolPath(ipmitoolPath string) Option {
function New (line 77) | func New(host, user, pass string, opts ...Option) (*Conn, error) {
FILE: providers/ipmitool/ipmitool_test.go
function TestMain (line 14) | func TestMain(m *testing.M) {
function TestPowerState (line 38) | func TestPowerState(t *testing.T) {
function TestPowerSet1 (line 56) | func TestPowerSet1(t *testing.T) {
function TestBootDeviceSet2 (line 74) | func TestBootDeviceSet2(t *testing.T) {
function TestBMCReset (line 92) | func TestBMCReset(t *testing.T) {
function TestDeactivateSOL (line 110) | func TestDeactivateSOL(t *testing.T) {
function TestSystemEventLogClear (line 128) | func TestSystemEventLogClear(t *testing.T) {
function TestSystemEventLogGet (line 146) | func TestSystemEventLogGet(t *testing.T) {
function TestSystemEventLogGetRaw (line 164) | func TestSystemEventLogGetRaw(t *testing.T) {
function TestSendNMI (line 182) | func TestSendNMI(t *testing.T) {
FILE: providers/openbmc/firmware.go
method FirmwareInstallSteps (line 20) | func (c *Conn) FirmwareInstallSteps(ctx context.Context, component strin...
method FirmwareInstallUploadAndInitiate (line 42) | func (c *Conn) FirmwareInstallUploadAndInitiate(ctx context.Context, com...
method checkQueueability (line 74) | func (c *Conn) checkQueueability(component string, tasks []*schemas.Task...
method FirmwareTaskStatus (line 98) | func (c *Conn) FirmwareTaskStatus(ctx context.Context, kind constants.Fi...
FILE: providers/openbmc/openbmc.go
constant ProviderName (line 22) | ProviderName = "openbmc"
constant ProviderProtocol (line 24) | ProviderProtocol = "redfish"
type Config (line 42) | type Config struct
type Option (line 51) | type Option
function WithHttpClient (line 53) | func WithHttpClient(httpClient *http.Client) Option {
function WithPort (line 59) | func WithPort(port string) Option {
function WithRootCAs (line 65) | func WithRootCAs(rootCAs *x509.CertPool) Option {
function WithUseBasicAuth (line 71) | func WithUseBasicAuth(useBasicAuth bool) Option {
type Conn (line 78) | type Conn struct
method Open (line 116) | func (c *Conn) Open(ctx context.Context) (err error) {
method deviceSupported (line 128) | func (c *Conn) deviceSupported(ctx context.Context) error {
method Close (line 159) | func (c *Conn) Close(ctx context.Context) error {
method Name (line 164) | func (c *Conn) Name() string {
method PowerStateGet (line 169) | func (c *Conn) PowerStateGet(ctx context.Context) (state string, err e...
method PowerSet (line 174) | func (c *Conn) PowerSet(ctx context.Context, state string) (ok bool, e...
method Inventory (line 179) | func (c *Conn) Inventory(ctx context.Context) (device *common.Device, ...
method BmcReset (line 184) | func (c *Conn) BmcReset(ctx context.Context, resetType string) (ok boo...
method SendNMI (line 189) | func (c *Conn) SendNMI(ctx context.Context) error {
function New (line 86) | func New(host, user, pass string, log logr.Logger, opts ...Option) *Conn {
FILE: providers/providers.go
constant FeaturePowerState (line 9) | FeaturePowerState registrar.Feature = "powerstate"
constant FeaturePowerSet (line 11) | FeaturePowerSet registrar.Feature = "powerset"
constant FeatureUserCreate (line 13) | FeatureUserCreate registrar.Feature = "usercreate"
constant FeatureUserDelete (line 15) | FeatureUserDelete registrar.Feature = "userdelete"
constant FeatureUserUpdate (line 17) | FeatureUserUpdate registrar.Feature = "userupdate"
constant FeatureUserRead (line 19) | FeatureUserRead registrar.Feature = "userread"
constant FeatureBmcReset (line 21) | FeatureBmcReset registrar.Feature = "bmcreset"
constant FeatureBootDeviceSet (line 23) | FeatureBootDeviceSet registrar.Feature = "bootdeviceset"
constant FeatureVirtualMedia (line 25) | FeatureVirtualMedia registrar.Feature = "virtualmedia"
constant FeatureMountFloppyImage (line 29) | FeatureMountFloppyImage registrar.Feature = "mountFloppyImage"
constant FeatureUnmountFloppyImage (line 31) | FeatureUnmountFloppyImage registrar.Feature = "unmountFloppyImage"
constant FeatureFirmwareInstall (line 34) | FeatureFirmwareInstall registrar.Feature = "firmwareinstall"
constant FeatureFirmwareInstallStatus (line 36) | FeatureFirmwareInstallStatus registrar.Feature = "firmwareinstallstatus"
constant FeatureInventoryRead (line 38) | FeatureInventoryRead registrar.Feature = "inventoryread"
constant FeaturePostCodeRead (line 40) | FeaturePostCodeRead registrar.Feature = "postcoderead"
constant FeatureScreenshot (line 42) | FeatureScreenshot registrar.Feature = "screenshot"
constant FeatureClearSystemEventLog (line 44) | FeatureClearSystemEventLog registrar.Feature = "clearsystemeventlog"
constant FeatureGetSystemEventLog (line 46) | FeatureGetSystemEventLog registrar.Feature = "getsystemeventlog"
constant FeatureGetSystemEventLogRaw (line 48) | FeatureGetSystemEventLogRaw registrar.Feature = "getsystemeventlograw"
constant FeatureFirmwareInstallSteps (line 50) | FeatureFirmwareInstallSteps registrar.Feature = "firmwareinstallsteps"
constant FeatureFirmwareUpload (line 53) | FeatureFirmwareUpload registrar.Feature = "firmwareupload"
constant FeatureFirmwareInstallUploaded (line 56) | FeatureFirmwareInstallUploaded registrar.Feature = "firmwareinstalluploa...
constant FeatureFirmwareTaskStatus (line 59) | FeatureFirmwareTaskStatus registrar.Feature = "firmwaretaskstatus"
constant FeatureFirmwareUploadInitiateInstall (line 62) | FeatureFirmwareUploadInitiateInstall registrar.Feature = "uploadandiniti...
constant FeatureDeactivateSOL (line 65) | FeatureDeactivateSOL registrar.Feature = "deactivatesol"
constant FeatureResetBiosConfiguration (line 68) | FeatureResetBiosConfiguration registrar.Feature = "resetbiosconfig"
constant FeatureSetBiosConfiguration (line 71) | FeatureSetBiosConfiguration registrar.Feature = "setbiosconfig"
constant FeatureSetBiosConfigurationFromFile (line 74) | FeatureSetBiosConfigurationFromFile registrar.Feature = "setbiosconfigfile"
constant FeatureGetBiosConfiguration (line 77) | FeatureGetBiosConfiguration registrar.Feature = "getbiosconfig"
constant FeatureBootProgress (line 80) | FeatureBootProgress registrar.Feature = "bootprogress"
FILE: providers/redfish/main_test.go
constant fixturesDir (line 17) | fixturesDir = "./fixtures"
function jsonResponse (line 27) | func jsonResponse(endpoint string) []byte {
function TestMain (line 57) | func TestMain(m *testing.M) {
function serviceRoot (line 76) | func serviceRoot(w http.ResponseWriter, r *http.Request) {
function sessionService (line 85) | func sessionService(w http.ResponseWriter, r *http.Request) {
FILE: providers/redfish/redfish.go
constant ProviderName (line 21) | ProviderName = "gofish"
constant ProviderProtocol (line 23) | ProviderProtocol = "redfish"
type Conn (line 46) | type Conn struct
method Open (line 146) | func (c *Conn) Open(ctx context.Context) (err error) {
method Close (line 151) | func (c *Conn) Close(ctx context.Context) error {
method Name (line 156) | func (c *Conn) Name() string {
method Compatible (line 161) | func (c *Conn) Compatible(ctx context.Context) bool {
method BmcReset (line 194) | func (c *Conn) BmcReset(ctx context.Context, resetType string) (ok boo...
method PowerStateGet (line 199) | func (c *Conn) PowerStateGet(ctx context.Context) (state string, err e...
method PowerSet (line 204) | func (c *Conn) PowerSet(ctx context.Context, state string) (ok bool, e...
method BootDeviceSet (line 209) | func (c *Conn) BootDeviceSet(ctx context.Context, bootDevice string, s...
method BootDeviceOverrideGet (line 214) | func (c *Conn) BootDeviceOverrideGet(ctx context.Context) (bmc.BootDev...
method SetVirtualMedia (line 219) | func (c *Conn) SetVirtualMedia(ctx context.Context, kind string, media...
method Inventory (line 224) | func (c *Conn) Inventory(ctx context.Context) (device *common.Device, ...
method GetBiosConfiguration (line 229) | func (c *Conn) GetBiosConfiguration(ctx context.Context) (biosConfig m...
method SetBiosConfiguration (line 234) | func (c *Conn) SetBiosConfiguration(ctx context.Context, biosConfig ma...
method ResetBiosConfiguration (line 239) | func (c *Conn) ResetBiosConfiguration(ctx context.Context) (err error) {
method SendNMI (line 244) | func (c *Conn) SendNMI(ctx context.Context) error {
type Config (line 52) | type Config struct
type Option (line 68) | type Option
function WithHttpClient (line 70) | func WithHttpClient(httpClient *http.Client) Option {
function WithPort (line 76) | func WithPort(port string) Option {
function WithVersionsNotCompatible (line 82) | func WithVersionsNotCompatible(versionsNotCompatible []string) Option {
function WithRootCAs (line 88) | func WithRootCAs(rootCAs *x509.CertPool) Option {
function WithUseBasicAuth (line 94) | func WithUseBasicAuth(useBasicAuth bool) Option {
function WithSystemName (line 100) | func WithSystemName(name string) Option {
function WithEtagMatchDisabled (line 109) | func WithEtagMatchDisabled(d bool) Option {
function New (line 116) | func New(host, user, pass string, log logr.Logger, opts ...Option) *Conn {
FILE: providers/redfish/sel.go
method ClearSystemEventLog (line 5) | func (c *Conn) ClearSystemEventLog(ctx context.Context) (err error) {
method GetSystemEventLog (line 9) | func (c *Conn) GetSystemEventLog(ctx context.Context) (entries [][]strin...
method GetSystemEventLogRaw (line 13) | func (c *Conn) GetSystemEventLogRaw(ctx context.Context) (eventlog strin...
FILE: providers/redfish/sel_test.go
function Test_GetSystemEventLog (line 11) | func Test_GetSystemEventLog(t *testing.T) {
function Test_GetSystemEventLogRaw (line 22) | func Test_GetSystemEventLogRaw(t *testing.T) {
FILE: providers/redfish/user.go
method UserRead (line 21) | func (c *Conn) UserRead(ctx context.Context) (users []map[string]string,...
method UserUpdate (line 50) | func (c *Conn) UserUpdate(ctx context.Context, user, pass, role string) ...
method UserCreate (line 87) | func (c *Conn) UserCreate(ctx context.Context, user, pass, role string) ...
method UserDelete (line 138) | func (c *Conn) UserDelete(ctx context.Context, user string) (ok bool, er...
FILE: providers/rpc/experimental.go
method embedPayload (line 9) | func (p *RequestPayload) embedPayload(rawJSON []byte, dotPath string) ([...
FILE: providers/rpc/http.go
method createRequest (line 14) | func (p *Provider) createRequest(ctx context.Context, rp RequestPayload)...
method handleResponse (line 47) | func (p *Provider) handleResponse(statusCode int, headers http.Header, b...
FILE: providers/rpc/http_test.go
function testRequest (line 17) | func testRequest(method, reqURL string, body RequestPayload, headers htt...
function TestRequestKVS (line 25) | func TestRequestKVS(t *testing.T) {
function TestResponseKVS (line 61) | func TestResponseKVS(t *testing.T) {
function TestCreateRequest (line 87) | func TestCreateRequest(t *testing.T) {
function TestContentSize (line 134) | func TestContentSize(t *testing.T) {
FILE: providers/rpc/logging.go
type requestDetails (line 9) | type requestDetails struct
type responseDetails (line 16) | type responseDetails struct
function requestKVS (line 23) | func requestKVS(method, url string, headers http.Header, body *bytes.Buf...
function responseKVS (line 41) | func responseKVS(statusCode int, headers http.Header, body *bytes.Buffer...
FILE: providers/rpc/payload.go
type Method (line 5) | type Method
constant BootDeviceMethod (line 8) | BootDeviceMethod Method = "setBootDevice"
constant PowerSetMethod (line 9) | PowerSetMethod Method = "setPowerState"
constant PowerGetMethod (line 10) | PowerGetMethod Method = "getPowerState"
constant VirtualMediaMethod (line 11) | VirtualMediaMethod Method = "setVirtualMedia"
constant PingMethod (line 12) | PingMethod Method = "ping"
type RequestPayload (line 16) | type RequestPayload struct
type BootDeviceParams (line 24) | type BootDeviceParams struct
type PowerSetParams (line 31) | type PowerSetParams struct
type VirtualMediaParams (line 36) | type VirtualMediaParams struct
type ResponsePayload (line 44) | type ResponsePayload struct
type ResponseError (line 52) | type ResponseError struct
method String (line 68) | func (r *ResponseError) String() string {
type PowerGetResult (line 57) | type PowerGetResult
method String (line 64) | func (p PowerGetResult) String() string {
constant PoweredOn (line 60) | PoweredOn PowerGetResult = "on"
constant PoweredOff (line 61) | PoweredOff PowerGetResult = "off"
FILE: providers/rpc/rpc.go
constant ProviderName (line 23) | ProviderName = "rpc"
constant ProviderProtocol (line 25) | ProviderProtocol = "http"
constant timestampHeader (line 28) | timestampHeader = "X-BMCLIB-Timestamp"
constant signatureHeader (line 29) | signatureHeader = "X-BMCLIB-Signature"
constant contentType (line 30) | contentType = "application/json"
constant maxContentLenAllowed (line 31) | maxContentLenAllowed = 512 << (10 * 1)
constant SHA256 (line 34) | SHA256 Algorithm = "sha256"
constant SHA256Short (line 36) | SHA256Short Algorithm = "256"
constant SHA512 (line 38) | SHA512 Algorithm = "sha512"
constant SHA512Short (line 40) | SHA512Short Algorithm = "512"
type Algorithm (line 51) | type Algorithm
type Secrets (line 55) | type Secrets
type Signatures (line 58) | type Signatures
type Provider (line 61) | type Provider struct
method Name (line 169) | func (p *Provider) Name() string {
method Open (line 176) | func (p *Provider) Open(ctx context.Context) error {
method Close (line 197) | func (p *Provider) Close(_ context.Context) (err error) {
method BootDeviceSet (line 202) | func (p *Provider) BootDeviceSet(ctx context.Context, bootDevice strin...
method PowerSet (line 225) | func (p *Provider) PowerSet(ctx context.Context, state string) (ok boo...
method PowerStateGet (line 246) | func (p *Provider) PowerStateGet(ctx context.Context) (state string, e...
method process (line 269) | func (p *Provider) process(ctx context.Context, rp RequestPayload) (Re...
method Transformer (line 347) | func (p *Provider) Transformer(typ reflect.Type) func(dst, src reflect...
type Opts (line 80) | type Opts struct
type RequestOpts (line 91) | type RequestOpts struct
type SignatureOpts (line 104) | type SignatureOpts struct
type HMACOpts (line 117) | type HMACOpts struct
type Experimental (line 126) | type Experimental struct
function New (line 134) | func New(consumerURL string, host string, secrets Secrets) *Provider {
FILE: providers/rpc/rpc_test.go
function TestOpen (line 13) | func TestOpen(t *testing.T) {
function TestBootDeviceSet (line 43) | func TestBootDeviceSet(t *testing.T) {
function TestPowerSet (line 81) | func TestPowerSet(t *testing.T) {
function TestPowerStateGet (line 121) | func TestPowerStateGet(t *testing.T) {
function TestServerErrors (line 161) | func TestServerErrors(t *testing.T) {
type testConsumer (line 190) | type testConsumer struct
method testServer (line 195) | func (t testConsumer) testServer() *httptest.Server {
FILE: providers/rpc/signature.go
type Hashes (line 14) | type Hashes
function createSignaturePayload (line 18) | func createSignaturePayload(body []byte, h http.Header) []byte {
function sign (line 29) | func sign(data []byte, h Hashes, prefixSigDisabled bool) (Signatures, er...
method ToShort (line 50) | func (a Algorithm) ToShort() Algorithm {
function NewSHA256 (line 62) | func NewSHA256(secret ...string) Hashes {
function NewSHA512 (line 71) | func NewSHA512(secret ...string) Hashes {
function mergeHashes (line 79) | func mergeHashes(hs ...Hashes) Hashes {
function CreateHashes (line 90) | func CreateHashes(s Secrets) map[Algorithm][]hash.Hash {
FILE: providers/supermicro/errors.go
type UnexpectedResponseError (line 20) | type UnexpectedResponseError struct
method Error (line 26) | func (e *UnexpectedResponseError) Error() string {
function unexpectedResponseErr (line 35) | func unexpectedResponseErr(payload, response []byte, statusCode int) err...
FILE: providers/supermicro/firmware.go
method FirmwareInstallSteps (line 37) | func (c *Client) FirmwareInstallSteps(ctx context.Context, component str...
method FirmwareUpload (line 45) | func (c *Client) FirmwareUpload(ctx context.Context, component string, f...
method FirmwareInstallUploaded (line 59) | func (c *Client) FirmwareInstallUploaded(ctx context.Context, component,...
method FirmwareTaskStatus (line 73) | func (c *Client) FirmwareTaskStatus(ctx context.Context, kind constants....
FILE: providers/supermicro/firmware_bios_test.go
function Test_setComponentUpdateMisc (line 16) | func Test_setComponentUpdateMisc(t *testing.T) {
function Test_setBIOSFirmwareInstallMode (line 102) | func Test_setBIOSFirmwareInstallMode(t *testing.T) {
FILE: providers/supermicro/floppy.go
method floppyImageMounted (line 22) | func (c *Client) floppyImageMounted(ctx context.Context) (bool, error) {
method MountFloppyImage (line 41) | func (c *Client) MountFloppyImage(ctx context.Context, image io.Reader) ...
method UnmountFloppyImage (line 131) | func (c *Client) UnmountFloppyImage(ctx context.Context) error {
FILE: providers/supermicro/supermicro.go
constant ProviderName (line 37) | ProviderName = "supermicro"
constant ProviderProtocol (line 39) | ProviderProtocol = "vendorapi"
type Config (line 80) | type Config struct
type Option (line 87) | type Option
function WithHttpClient (line 89) | func WithHttpClient(httpClient *http.Client) Option {
function WithSecureTLS (line 96) | func WithSecureTLS(rootCAs *x509.CertPool) Option {
function WithPort (line 102) | func WithPort(port string) Option {
type Client (line 109) | type Client struct
method login (line 153) | func (c *Client) login(ctx context.Context, encodeCreds bool) error {
method Open (line 190) | func (c *Client) Open(ctx context.Context) (err error) {
method PowerStateGet (line 238) | func (c *Client) PowerStateGet(ctx context.Context) (state string, err...
method PowerSet (line 247) | func (c *Client) PowerSet(ctx context.Context, state string) (ok bool,...
method BmcReset (line 256) | func (c *Client) BmcReset(ctx context.Context, resetType string) (ok b...
method Inventory (line 265) | func (c *Client) Inventory(ctx context.Context) (device *common.Device...
method GetBiosConfiguration (line 274) | func (c *Client) GetBiosConfiguration(ctx context.Context) (biosConfig...
method SetBiosConfiguration (line 283) | func (c *Client) SetBiosConfiguration(ctx context.Context, biosConfig ...
method SetBiosConfigurationFromFile (line 292) | func (c *Client) SetBiosConfigurationFromFile(ctx context.Context, cfg...
method ResetBiosConfiguration (line 301) | func (c *Client) ResetBiosConfiguration(ctx context.Context) (err erro...
method bmcQueryor (line 309) | func (c *Client) bmcQueryor(ctx context.Context) (bmcQueryor, error) {
method Close (line 373) | func (c *Client) Close(ctx context.Context) error {
method Name (line 400) | func (c *Client) Name() string {
method Screenshot (line 404) | func (c *Client) Screenshot(ctx context.Context) (image []byte, fileTy...
method fetchScreenPreview (line 424) | func (c *Client) fetchScreenPreview(ctx context.Context) ([]byte, erro...
method initScreenPreview (line 440) | func (c *Client) initScreenPreview(ctx context.Context) error {
method SendNMI (line 644) | func (c *Client) SendNMI(ctx context.Context) error {
method GetBootProgress (line 649) | func (c *Client) GetBootProgress() (*schemas.BootProgress, error) {
method BootComplete (line 654) | func (c *Client) BootComplete() (bool, error) {
type bmcQueryor (line 115) | type bmcQueryor interface
function NewClient (line 130) | func NewClient(host, user, pass string, log logr.Logger, opts ...Option)...
function parseToken (line 345) | func parseToken(body []byte) string {
type serviceClient (line 461) | type serviceClient struct
method setCsrfToken (line 495) | func (c *serviceClient) setCsrfToken(t string) {
method redfishSession (line 499) | func (c *serviceClient) redfishSession(ctx context.Context) (err error) {
method supportsFirmwareInstall (line 518) | func (c *serviceClient) supportsFirmwareInstall(model string) error {
method query (line 532) | func (c *serviceClient) query(ctx context.Context, endpoint, method st...
function newBmcServiceClient (line 472) | func newBmcServiceClient(host, port, user, pass string, client *http.Cli...
function hostIP (line 629) | func hostIP(hostURL string) (string, error) {
FILE: providers/supermicro/supermicro_test.go
constant fixturesDir (line 19) | fixturesDir = "./fixtures"
function TestParseToken (line 22) | func TestParseToken(t *testing.T) {
function mustReadFile (line 75) | func mustReadFile(t *testing.T, filename string) []byte {
function TestOpen (line 106) | func TestOpen(t *testing.T) {
function TestClose (line 243) | func TestClose(t *testing.T) {
function TestInitScreenPreview (line 299) | func TestInitScreenPreview(t *testing.T) {
function TestFetchScreenPreview (line 362) | func TestFetchScreenPreview(t *testing.T) {
FILE: providers/supermicro/types.go
type IPMI (line 3) | type IPMI struct
type FruInfo (line 8) | type FruInfo struct
type Board (line 13) | type Board struct
FILE: providers/supermicro/x11.go
type x11 (line 22) | type x11 struct
method deviceModel (line 35) | func (c *x11) deviceModel() string {
method queryDeviceModel (line 39) | func (c *x11) queryDeviceModel(ctx context.Context) (string, error) {
method deviceModelFromFruInfo (line 56) | func (c *x11) deviceModelFromFruInfo(ctx context.Context) (string, err...
method deviceModelFromBoardID (line 75) | func (c *x11) deviceModelFromBoardID(ctx context.Context) (string, err...
method fruInfo (line 110) | func (c *x11) fruInfo(ctx context.Context) (*FruInfo, error) {
method supportsInstall (line 136) | func (c *x11) supportsInstall(component string) error {
method firmwareInstallSteps (line 147) | func (c *x11) firmwareInstallSteps(component string) ([]constants.Firm...
method firmwareUpload (line 167) | func (c *x11) firmwareUpload(ctx context.Context, component string, fi...
method firmwareInstallUploaded (line 180) | func (c *x11) firmwareInstallUploaded(ctx context.Context, component, ...
method firmwareTaskStatus (line 193) | func (c *x11) firmwareTaskStatus(ctx context.Context, component, _ str...
method getBootProgress (line 206) | func (c *x11) getBootProgress() (*schemas.BootProgress, error) {
method bootComplete (line 210) | func (c *x11) bootComplete() (bool, error) {
function newX11Client (line 28) | func newX11Client(client *serviceClient, logger logr.Logger) bmcQueryor {
FILE: providers/supermicro/x11_firmware_bios.go
method firmwareUploadBIOS (line 22) | func (c *x11) firmwareUploadBIOS(ctx context.Context, reader io.Reader) ...
method firmwareInstallUploadedBIOS (line 57) | func (c *x11) firmwareInstallUploadedBIOS(ctx context.Context) error {
method checkComponentUpdateMisc (line 71) | func (c *x11) checkComponentUpdateMisc(ctx context.Context, stage string...
method setBIOSFirmwareInstallMode (line 121) | func (c *x11) setBIOSFirmwareInstallMode(ctx context.Context) error {
method setBiosUpdateStart (line 165) | func (c *x11) setBiosUpdateStart(ctx context.Context) error {
method uploadBIOSFirmware (line 194) | func (c *x11) uploadBIOSFirmware(ctx context.Context, fwReader io.Reader...
method verifyBIOSFirmwareVersion (line 276) | func (c *x11) verifyBIOSFirmwareVersion(ctx context.Context) error {
method setBIOSOp (line 308) | func (c *x11) setBIOSOp(ctx context.Context) error {
method initiateBIOSFirmwareInstall (line 328) | func (c *x11) initiateBIOSFirmwareInstall(ctx context.Context) error {
method setBIOSUpdateDone (line 358) | func (c *x11) setBIOSUpdateDone(ctx context.Context) error {
method statusBIOSFirmwareInstall (line 379) | func (c *x11) statusBIOSFirmwareInstall(ctx context.Context) (state cons...
FILE: providers/supermicro/x11_firmware_bmc.go
method firmwareUploadBMC (line 28) | func (c *x11) firmwareUploadBMC(ctx context.Context, reader io.Reader) e...
method setBMCFirmwareInstallMode (line 51) | func (c *x11) setBMCFirmwareInstallMode(ctx context.Context) error {
method uploadBMCFirmware (line 105) | func (c *x11) uploadBMCFirmware(ctx context.Context, fwReader io.Reader)...
method verifyBMCFirmwareVersion (line 187) | func (c *x11) verifyBMCFirmwareVersion(ctx context.Context) error {
method initiateBMCFirmwareInstall (line 213) | func (c *x11) initiateBMCFirmwareInstall(ctx context.Context) error {
method statusBMCFirmwareInstall (line 246) | func (c *x11) statusBMCFirmwareInstall(ctx context.Context) (state const...
FILE: providers/supermicro/x11_firmware_bmc_test.go
function TestX11SetBMCFirmwareInstallMode (line 22) | func TestX11SetBMCFirmwareInstallMode(t *testing.T) {
function TestX11UploadBMCFirmware (line 112) | func TestX11UploadBMCFirmware(t *testing.T) {
function TestX11VerifyBMCFirmwareVersion (line 207) | func TestX11VerifyBMCFirmwareVersion(t *testing.T) {
function TestX11InitiateBMCFirmwareInstall (line 289) | func TestX11InitiateBMCFirmwareInstall(t *testing.T) {
function TestX11StatusBMCFirmwareInstall (line 371) | func TestX11StatusBMCFirmwareInstall(t *testing.T) {
FILE: providers/supermicro/x12.go
type x12 (line 20) | type x12 struct
method deviceModel (line 33) | func (c *x12) deviceModel() string {
method queryDeviceModel (line 37) | func (c *x12) queryDeviceModel(ctx context.Context) (string, error) {
method supportsInstall (line 60) | func (c *x12) supportsInstall(component string) error {
method firmwareInstallSteps (line 71) | func (c *x12) firmwareInstallSteps(component string) ([]constants.Firm...
method firmwareUpload (line 85) | func (c *x12) firmwareUpload(ctx context.Context, component string, fi...
method firmwareTaskActive (line 122) | func (c *x12) firmwareTaskActive(ctx context.Context, component string...
method biosFwInstallParams (line 202) | func (c *x12) biosFwInstallParams() (map[string]bool, error) {
method bmcFwInstallParams (line 230) | func (c *x12) bmcFwInstallParams() map[string]bool {
method redfishParameters (line 238) | func (c *x12) redfishParameters(component, targetODataID string) (*rfw...
method redfishOdataID (line 271) | func (c *x12) redfishOdataID(ctx context.Context, component string) (s...
method firmwareInstallUploaded (line 286) | func (c *x12) firmwareInstallUploaded(ctx context.Context, component, ...
method firmwareTaskStatus (line 310) | func (c *x12) firmwareTaskStatus(ctx context.Context, component, taskI...
method getBootProgress (line 318) | func (c *x12) getBootProgress() (*schemas.BootProgress, error) {
method bootComplete (line 327) | func (c *x12) bootComplete() (bool, error) {
function newX12Client (line 26) | func newX12Client(client *serviceClient, logger logr.Logger) bmcQueryor {
function noTasksRunning (line 144) | func noTasksRunning(component string, t *schemas.Task) error {
function stateFinalized (line 181) | func stateFinalized(s schemas.TaskState) bool {
type Supermicro (line 192) | type Supermicro struct
type OEM (line 197) | type OEM struct
Condensed preview — 219 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,201K chars).
[
{
"path": ".devcontainer/Dockerfile",
"chars": 100,
"preview": "FROM mcr.microsoft.com/devcontainers/go:1-1.22-bullseye\nRUN apt update\nRUN apt install ipmitool -y\n\n"
},
{
"path": ".devcontainer/devcontainer.json",
"chars": 1038,
"preview": "// For format details, see https://aka.ms/devcontainer.json. For config options, see the\n// README at: https://github.co"
},
{
"path": ".github/ISSUE_TEMPLATE/default.md",
"chars": 321,
"preview": "Please don't forget to include the following information in your issue:\n\n- The HW vendor impacted by this issue (if appl"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 490,
"preview": "## What does this PR implement/change/remove?\n\n### Checklist\n- [ ] Tests added\n- [ ] Similar commits squashed\n\n### The H"
},
{
"path": ".github/mergify.yml",
"chars": 743,
"preview": "queue_rules:\n - name: default\n batch_size: 1\n queue_conditions:\n - base=main\n - \"#approved-reviews-by>="
},
{
"path": ".github/workflows/ci.yaml",
"chars": 915,
"preview": "name: For each commit and PR\non:\n push:\n pull_request:\n\njobs:\n lint:\n runs-on: ubuntu-latest\n env:\n CGO_EN"
},
{
"path": ".gitignore",
"chars": 457,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n# Ou"
},
{
"path": ".golangci.yml",
"chars": 3776,
"preview": " govet:\n auto-fix: true\n linters-settings:\n enable:\n - fieldalignment\n check-shadowing: true\n settin"
},
{
"path": "LICENSE",
"chars": 11348,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 541,
"preview": "help:\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | cut -d\":\" -f2,3 | awk 'BEGIN {FS = \":.*?## \"}; {prin"
},
{
"path": "README.md",
"chars": 10610,
"preview": "# bmclib v2 - board management controller library\n\n[\n\n// Metadata"
},
{
"path": "bmc/boot_device.go",
"chars": 6039,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n)\n\ntype "
},
{
"path": "bmc/boot_device_test.go",
"chars": 7242,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"fmt\"\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/hashi"
},
{
"path": "bmc/connection.go",
"chars": 5047,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n"
},
{
"path": "bmc/connection_test.go",
"chars": 5290,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/hashicorp/go"
},
{
"path": "bmc/firmware.go",
"chars": 21103,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/constants\"\n\tbconsts \"github.com/"
},
{
"path": "bmc/firmware_test.go",
"chars": 22681,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/constants\"\n\tbmclibEr"
},
{
"path": "bmc/floppy.go",
"chars": 4562,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"github.com/hashic"
},
{
"path": "bmc/floppy_test.go",
"chars": 2984,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"githu"
},
{
"path": "bmc/inventory.go",
"chars": 2375,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n\n\tbmclibErrs \"gi"
},
{
"path": "bmc/inventory_test.go",
"chars": 3095,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/errors\"\n\tbmclibErrs \"github.com/"
},
{
"path": "bmc/nmi.go",
"chars": 1564,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n)\n\ntype NMISender inter"
},
{
"path": "bmc/nmi_test.go",
"chars": 2973,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nt"
},
{
"path": "bmc/postcode.go",
"chars": 2538,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"github.com/hashicorp/go"
},
{
"path": "bmc/postcode_test.go",
"chars": 3241,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/constants\"\n\tbmclibErrs \"github.c"
},
{
"path": "bmc/power.go",
"chars": 5630,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n)\n\n// Po"
},
{
"path": "bmc/power_test.go",
"chars": 6466,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/hashicorp/go"
},
{
"path": "bmc/provider.go",
"chars": 502,
"preview": "package bmc\n\nimport \"fmt\"\n\n// Provider interface describes details about a provider\ntype Provider interface {\n\t// Name o"
},
{
"path": "bmc/reset.go",
"chars": 2495,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n)\n\n// BM"
},
{
"path": "bmc/reset_test.go",
"chars": 3553,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/hashicorp/go"
},
{
"path": "bmc/screenshot.go",
"chars": 2358,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"github.com/hashicorp/go"
},
{
"path": "bmc/screenshot_test.go",
"chars": 3602,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"gopkg.in/go-playg"
},
{
"path": "bmc/sel.go",
"chars": 5707,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n)\n\n// Sy"
},
{
"path": "bmc/sel_test.go",
"chars": 5110,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nt"
},
{
"path": "bmc/sol.go",
"chars": 2269,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n)\n\n// SO"
},
{
"path": "bmc/sol_test.go",
"chars": 2798,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/hashicorp/go"
},
{
"path": "bmc/user.go",
"chars": 8365,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/hashicorp/go-multierror\"\n)\n\n// UserCreator creat"
},
{
"path": "bmc/user_test.go",
"chars": 12909,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/hashicorp/go"
},
{
"path": "bmc/virtual_media.go",
"chars": 2478,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/hashicorp/go-multierror\"\n\t\"github.com/pkg/errors\"\n)\n\n// VirtualMed"
},
{
"path": "bmc/virtual_media_test.go",
"chars": 3975,
"preview": "package bmc\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/google/go-cmp/cmp\"\n\t\"github.com/hashicorp/go"
},
{
"path": "client.go",
"chars": 29350,
"preview": "// Package bmclib client.go is intended to be the main public API.\n// Its purpose is to make interacting with bmclib as "
},
{
"path": "client_test.go",
"chars": 5595,
"preview": "package bmclib\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/logging\"\n\t\"github.com/google/"
},
{
"path": "constants/constants.go",
"chars": 5324,
"preview": "package constants\n\ntype (\n\t// Redfish operation apply time parameter\n\tOperationApplyTime string\n\n\t// The FirmwareInstall"
},
{
"path": "doc.go",
"chars": 288,
"preview": "// Copyright 2022 The bmclib Authors. All rights reserved.\n// Use of this source code is governed by an Apache that can "
},
{
"path": "errors/errors.go",
"chars": 6706,
"preview": "package errors\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\t// ErrLoginFailed is returned when we fail to login to a bmc\n\tErrLog"
},
{
"path": "examples/bios/doc.go",
"chars": 197,
"preview": "/*\nbios is an example commmand that retrieves BIOS configuration information and prints it out\n\n\t$ BMC_HOST=1.2.3.4 BMC_"
},
{
"path": "examples/bios/main.go",
"chars": 2581,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tbmclib \"github.com/bm"
},
{
"path": "examples/create-users/doc.go",
"chars": 786,
"preview": "/*\ncreate-users is an example commmand that utilizes the 'v1' bmclib interface\nmethods to create user entries in a BMC u"
},
{
"path": "examples/create-users/main.go",
"chars": 2539,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"encoding/csv\"\n\t\"flag\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"time\"\n\n\tbmclib \"gith"
},
{
"path": "examples/floppy-image/doc.go",
"chars": 429,
"preview": "/*\ninventory is an example commmand that utilizes the 'v1' bmclib interface\nmethods to upload and mount, unmount a flopp"
},
{
"path": "examples/floppy-image/main.go",
"chars": 1851,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"flag\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\tbmclib \"github.com/bmc-toolbox/bmclib/v2"
},
{
"path": "examples/homeassistant/main.go",
"chars": 1592,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2\"\n\t\"github.com/bmc-toolbox/bmclib/v2/loggin"
},
{
"path": "examples/install-firmware/doc.go",
"chars": 3314,
"preview": "/*\ninstall-firmware is an example command that utilizes the 'v1' bmclib interface\nmethods to flash a firmware image to a"
},
{
"path": "examples/install-firmware/main.go",
"chars": 4239,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"flag\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tbmclib"
},
{
"path": "examples/inventory/doc.go",
"chars": 620,
"preview": "/*\ninventory is an example commmand that utilizes the 'v1' bmclib interface\nmethods to gather inventory from a BMC using"
},
{
"path": "examples/inventory/main.go",
"chars": 1983,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\tbmcli"
},
{
"path": "examples/inventory/output.json",
"chars": 12099,
"preview": "{\n \"oem\": false,\n \"vendor\": \"Dell Inc.\",\n \"model\": \"PowerEdge R6515\",\n \"serial\": \"FOOBAR\",\n \"bios\": {\n \"descript"
},
{
"path": "examples/reset_bmc/reset_bmc.go",
"chars": 875,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2\"\n\t\"github.com/bombsimon/logru"
},
{
"path": "examples/rpc/main.go",
"chars": 2199,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2\"\n\t\"github.com"
},
{
"path": "examples/screenshot/doc.go",
"chars": 582,
"preview": "/*\nstatus is an example commmand that utilizes the 'v1' bmclib interface methods\nto capture a screenshot.\n\n\t$ go run ./e"
},
{
"path": "examples/screenshot/main.go",
"chars": 2142,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmc"
},
{
"path": "examples/sel/main.go",
"chars": 2418,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"flag\"\n\t\"io/ioutil\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2\"\n\t\"git"
},
{
"path": "examples/status/doc.go",
"chars": 651,
"preview": "/*\nstatus is an example commmand that utilizes the 'v1' bmclib interface methods\nto gather the BMC version, power state,"
},
{
"path": "examples/status/main.go",
"chars": 1700,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"flag\"\n\t\"io/ioutil\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2\"\n\t\"git"
},
{
"path": "examples/virtualmedia/doc.go",
"chars": 381,
"preview": "/*\nVirtual Media is an example command to mount and umount virtual media (ISO) on a BMC.\n\n\t# mount an ISO\n\t$ go run exam"
},
{
"path": "examples/virtualmedia/main.go",
"chars": 1314,
"preview": "package main\n\nimport (\n\t\"context\"\n\t\"flag\"\n\t\"fmt\"\n\t\"log/slog\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2\"\n\t\"github"
},
{
"path": "filter.go",
"chars": 2333,
"preview": "package bmclib\n\nimport \"github.com/jacobweinstock/registrar\"\n\n// PreferProvider reorders the registry to have the given "
},
{
"path": "fixtures/internal/sum/ChangeBiosConfig",
"chars": 433,
"preview": "Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64)\nCopyright(C) 2013-2024 Super Micro Computer, Inc. "
},
{
"path": "fixtures/internal/sum/ChangeBiosConfig-Changed",
"chars": 363,
"preview": "Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64)\nCopyright(C) 2013-2024 Super Micro Computer, Inc. "
},
{
"path": "fixtures/internal/sum/ChangeBiosConfig-Changed-Reboot",
"chars": 647,
"preview": "Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64)\nCopyright(C) 2013-2024 Super Micro Computer, Inc. "
},
{
"path": "fixtures/internal/sum/GetBIOSInfo",
"chars": 341,
"preview": "Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64)\nCopyright(C) 2013-2024 Super Micro Computer, Inc. "
},
{
"path": "fixtures/internal/sum/GetBiosConfiguration",
"chars": 175194,
"preview": "Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64)\nCopyright(C) 2013-2024 Super Micro Computer, Inc. "
},
{
"path": "fixtures/internal/sum/SetBiosConfiguration",
"chars": 647,
"preview": "Supermicro Update Manager (for UEFI BIOS) 2.14.0 (2024/02/15) (ARM64)\nCopyright(C) 2013-2024 Super Micro Computer, Inc. "
},
{
"path": "go.mod",
"chars": 1468,
"preview": "module github.com/bmc-toolbox/bmclib/v2\n\ngo 1.21\n\nrequire (\n\tdario.cat/mergo v1.0.1\n\tgithub.com/Jeffail/gabs/v2 v2.7.0\n\t"
},
{
"path": "go.sum",
"chars": 8774,
"preview": "dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=\ndario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobSt"
},
{
"path": "internal/executor/errors.go",
"chars": 1740,
"preview": "package executor\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\nvar (\n\tErrNoCommandOutput = errors.New(\"command returned no o"
},
{
"path": "internal/executor/executor.go",
"chars": 2643,
"preview": "package executor\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/pkg/errors\"\n)\n\n// Executo"
},
{
"path": "internal/executor/executor_test.go",
"chars": 1848,
"preview": "package executor\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/pkg/errors\"\n\t\"github.com/s"
},
{
"path": "internal/executor/fake_executor.go",
"chars": 2045,
"preview": "package executor\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"strings\"\n)\n\n// FakeExecute implements the utils.Executor interface\n// to e"
},
{
"path": "internal/helper/helper.go",
"chars": 325,
"preview": "package helper\n\nimport (\n\t\"regexp\"\n\t\"runtime\"\n)\n\nvar basename = regexp.MustCompile(`^.+\\.(.*$)`)\n\n// WhosCalling returns"
},
{
"path": "internal/helper/helper_test.go",
"chars": 238,
"preview": "package helper\n\nimport \"testing\"\n\nfunc TestWhosCalling(t *testing.T) {\n\texpectedAnswer := \"TestWhosCalling\"\n\n\tanswer := "
},
{
"path": "internal/httpclient/httpclient.go",
"chars": 1949,
"preview": "package httpclient\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/cookiejar\"\n\t\"strings\"\n\t\"time\"\n\n\t"
},
{
"path": "internal/httpclient/httpclient_test.go",
"chars": 1641,
"preview": "package httpclient\n\nimport (\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc CertPo"
},
{
"path": "internal/ipmi/ipmi.go",
"chars": 12389,
"preview": "package ipmi\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\n\t\"github.com/go-logr/logr\"\n\t\"githu"
},
{
"path": "internal/redfishwrapper/bios.go",
"chars": 1596,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"github.com/stmcginn"
},
{
"path": "internal/redfishwrapper/bios_test.go",
"chars": 2323,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\""
},
{
"path": "internal/redfishwrapper/boot_device.go",
"chars": 4531,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/bmc\"\n\tbmclibErrs \"github.com/bmc-toolbox"
},
{
"path": "internal/redfishwrapper/client.go",
"chars": 9355,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings"
},
{
"path": "internal/redfishwrapper/client_test.go",
"chars": 7087,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\tbmclibErrs \"github."
},
{
"path": "internal/redfishwrapper/firmware.go",
"chars": 14567,
"preview": "package redfishwrapper\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/t"
},
{
"path": "internal/redfishwrapper/firmware_test.go",
"chars": 10434,
"preview": "package redfishwrapper\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"log\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/h"
},
{
"path": "internal/redfishwrapper/fixtures/dell/bios.json",
"chars": 9083,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#Bios.Bios\",\n \"@odata.id\": \"/redfish/v1/Systems/System.Embedded.1/Bios\""
},
{
"path": "internal/redfishwrapper/fixtures/dell/manager.idrac.embedded.1.json",
"chars": 1851,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#Manager.Manager\",\n \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1"
},
{
"path": "internal/redfishwrapper/fixtures/dell/managers.json",
"chars": 403,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ManagerCollection.ManagerCollection\",\n \"@odata.id\": \"/redfish/v1/Manag"
},
{
"path": "internal/redfishwrapper/fixtures/dell/serviceroot.json",
"chars": 2191,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ServiceRoot.ServiceRoot\",\n \"@odata.id\": \"/redfish/v1\",\n \"@odata.typ"
},
{
"path": "internal/redfishwrapper/fixtures/dell/system.embedded.1.json",
"chars": 19363,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n \"@odata.id\": \"/redfish/v1/Systems/Sys"
},
{
"path": "internal/redfishwrapper/fixtures/dell/system.embedded.1.virtualmedia.json",
"chars": 1244,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n \"@odata.id\": \"/redfish/v1/Systems/Sys"
},
{
"path": "internal/redfishwrapper/fixtures/dell/systems.json",
"chars": 446,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystemCollection.ComputerSystemCollection\",\n \"@odata.id\": \"/re"
},
{
"path": "internal/redfishwrapper/fixtures/dell/virtualmedia_1.json",
"chars": 1401,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#VirtualMedia.VirtualMedia\",\n \"@odata.id\": \"/redfish/v1/Systems/System."
},
{
"path": "internal/redfishwrapper/fixtures/dell/virtualmedia_2.json",
"chars": 1401,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#VirtualMedia.VirtualMedia\",\n \"@odata.id\": \"/redfish/v1/Systems/System."
},
{
"path": "internal/redfishwrapper/fixtures/dell/virtualmedia_collection.json",
"chars": 623,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#VirtualMediaCollection.VirtualMediaCollection\",\n \"@odata.id\": \"/redfis"
},
{
"path": "internal/redfishwrapper/fixtures/managers.json",
"chars": 301,
"preview": "{\n \"@odata.type\": \"#ManagerCollection.ManagerCollection\",\n \"@odata.id\": \"/redfish/v1/Managers\",\n \"Name\": \"Manag"
},
{
"path": "internal/redfishwrapper/fixtures/managers_1.json",
"chars": 2493,
"preview": "{\n \"@odata.type\": \"#Manager.v1_7_0.Manager\",\n \"@odata.id\": \"/redfish/v1/Managers/1\",\n \"Id\": \"1\",\n \"Name\": \"M"
},
{
"path": "internal/redfishwrapper/fixtures/serviceroot.json",
"chars": 1595,
"preview": "{\n \"@odata.type\": \"#ServiceRoot.v1_5_2.ServiceRoot\",\n \"@odata.id\": \"/redfish/v1\",\n \"Id\": \"ServiceRoot\",\n \"Na"
},
{
"path": "internal/redfishwrapper/fixtures/serviceroot_no_manager.json",
"chars": 1526,
"preview": "{\n \"@odata.type\": \"#ServiceRoot.v1_5_2.ServiceRoot\",\n \"@odata.id\": \"/redfish/v1\",\n \"Id\": \"ServiceRoot\",\n \"Na"
},
{
"path": "internal/redfishwrapper/fixtures/smc_1.14.0_serviceroot.json",
"chars": 1416,
"preview": "{\"@odata.type\":\"#ServiceRoot.v1_14_0.ServiceRoot\",\"@odata.id\":\"/redfish/v1\",\"Id\":\"ServiceRoot\",\"Name\":\"Root Service\",\"Re"
},
{
"path": "internal/redfishwrapper/fixtures/smc_1.14.0_systems.json",
"chars": 308,
"preview": "{\"@odata.type\":\"#ComputerSystemCollection.ComputerSystemCollection\",\"@odata.id\":\"/redfish/v1/Systems\",\"Name\":\"Computer S"
},
{
"path": "internal/redfishwrapper/fixtures/smc_1.14.0_systems_1.json",
"chars": 3636,
"preview": "{\"@odata.type\":\"#ComputerSystem.v1_16_0.ComputerSystem\",\"@odata.id\":\"/redfish/v1/Systems/1\",\"Id\":\"1\",\"Name\":\"System\",\"De"
},
{
"path": "internal/redfishwrapper/fixtures/smc_1.9.0_serviceroot.json",
"chars": 1214,
"preview": "{\"@odata.type\":\"#ServiceRoot.v1_5_2.ServiceRoot\",\"@odata.id\":\"/redfish/v1\",\"Id\":\"ServiceRoot\",\"Name\":\"Root Service\",\"Red"
},
{
"path": "internal/redfishwrapper/fixtures/systems.json",
"chars": 329,
"preview": "{\n \"@odata.type\": \"#ComputerSystemCollection.ComputerSystemCollection\",\n \"@odata.id\": \"/redfish/v1/Systems\",\n \""
},
{
"path": "internal/redfishwrapper/fixtures/systems_1.json",
"chars": 3165,
"preview": "{\n \"@odata.type\": \"#ComputerSystem.v1_8_0.ComputerSystem\",\n \"@odata.id\": \"/redfish/v1/Systems/1\",\n \"Id\": \"1\",\n "
},
{
"path": "internal/redfishwrapper/fixtures/systems_1_no_bios.json",
"chars": 3165,
"preview": "{\n \"@odata.type\": \"#ComputerSystem.v1_8_0.ComputerSystem\",\n \"@odata.id\": \"/redfish/v1/Systems/1\",\n \"Id\": \"1\",\n "
},
{
"path": "internal/redfishwrapper/fixtures/systems_bios.json",
"chars": 675,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#Bios.Bios\",\n \"@odata.id\": \"/redfish/v1/Systems/1/Bios\",\n \"@odata.ty"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_1_completed.json",
"chars": 686,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/1\",\n \"Id\": \"1\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_1_failed.json",
"chars": 683,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/1\",\n \"Id\": \"1\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_1_pending.json",
"chars": 684,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/1\",\n \"Id\": \"1\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_1_running.json",
"chars": 684,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/1\",\n \"Id\": \"1\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_1_scheduled.json",
"chars": 686,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/1\",\n \"Id\": \"1\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_1_starting.json",
"chars": 685,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/1\",\n \"Id\": \"1\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_1_unknown.json",
"chars": 685,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/1\",\n \"Id\": \"1\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks/tasks_2.json",
"chars": 686,
"preview": "{\n \"@odata.type\": \"#Task.v1_4_3.Task\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks/2\",\n \"Id\": \"2\",\n \"Name\":"
},
{
"path": "internal/redfishwrapper/fixtures/tasks.json",
"chars": 368,
"preview": "{\n \"@odata.type\": \"#TaskCollection.TaskCollection\",\n \"@odata.id\": \"/redfish/v1/TaskService/Tasks\",\n \"Id\": \"Task"
},
{
"path": "internal/redfishwrapper/fixtures/taskservice.json",
"chars": 478,
"preview": "{\n \"@odata.type\": \"#TaskService.v1_1_3.TaskService\",\n \"@odata.id\": \"/redfish/v1/TaskService\",\n \"Id\": \"TaskServi"
},
{
"path": "internal/redfishwrapper/fixtures/updateservice_disabled.json",
"chars": 1398,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#UpdateService.UpdateService\",\n \"@odata.id\": \"/redfish/v1/UpdateService"
},
{
"path": "internal/redfishwrapper/fixtures/updateservice_ok_response.json",
"chars": 756,
"preview": "{\n \"Accepted\": {\n \"code\": \"Base.v1_10_3.Accepted\",\n \"Message\": \"Successfully Accepted Request. Please s"
},
{
"path": "internal/redfishwrapper/fixtures/updateservice_unexpected_response.json",
"chars": 528,
"preview": "{\n \"Accepted\": {\n \"code\": \"Base.v1_10_3.Accepted\",\n \"Message\": \"Successfully Accepted Request. Please s"
},
{
"path": "internal/redfishwrapper/fixtures/updateservice_with_httppushuri.json",
"chars": 546,
"preview": "{\n \"@odata.id\": \"/redfish/v1/UpdateService\",\n \"@odata.type\": \"#UpdateService.v1_5_0.UpdateService\",\n \"Descripti"
},
{
"path": "internal/redfishwrapper/fixtures/updateservice_with_multipart.json",
"chars": 1397,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#UpdateService.UpdateService\",\n \"@odata.id\": \"/redfish/v1/UpdateService"
},
{
"path": "internal/redfishwrapper/inventory.go",
"chars": 7172,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"strings\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"github.c"
},
{
"path": "internal/redfishwrapper/inventory_collect.go",
"chars": 14412,
"preview": "package redfishwrapper\n\nimport (\n\t\"math\"\n\t\"strings\"\n\n\t\"github.com/bmc-toolbox/common\"\n\t\"github.com/stmcginnis/gofish\"\n\t\""
},
{
"path": "internal/redfishwrapper/inventory_collect_test.go",
"chars": 5729,
"preview": "package redfishwrapper\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/bmc-toolbox/common\"\n\t\"github.com/stmcginnis/gofish\""
},
{
"path": "internal/redfishwrapper/main_test.go",
"chars": 748,
"preview": "package redfishwrapper\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc mustReadFile(t *testing.T, filename s"
},
{
"path": "internal/redfishwrapper/power.go",
"chars": 4803,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/err"
},
{
"path": "internal/redfishwrapper/sel.go",
"chars": 2318,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"gi"
},
{
"path": "internal/redfishwrapper/system.go",
"chars": 3366,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\n\t\"github.com/"
},
{
"path": "internal/redfishwrapper/system_test.go",
"chars": 1749,
"preview": "package redfishwrapper\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stmcginnis/gofish/schemas\"\n\t\"github.com/stretchr/testify/asser"
},
{
"path": "internal/redfishwrapper/task.go",
"chars": 2400,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/constants\"\n\tbmclibErrs"
},
{
"path": "internal/redfishwrapper/task_test.go",
"chars": 8558,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/bmc-too"
},
{
"path": "internal/redfishwrapper/virtual_media.go",
"chars": 4205,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/stmcginnis/gofish\"\n\t\"github.com/stm"
},
{
"path": "internal/redfishwrapper/virtual_media_test.go",
"chars": 10210,
"preview": "package redfishwrapper\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/stretch"
},
{
"path": "internal/sum/sum.go",
"chars": 5640,
"preview": "package sum\n\n// SUM is Supermicro Update Manager\n// https://www.supermicro.com/en/solutions/management-software/supermic"
},
{
"path": "internal/sum/sum_test.go",
"chars": 1868,
"preview": "package sum\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\n\tex \"github.com/bmc-toolbox/bmclib/v2/internal/executor\"\n)\n\nfunc newF"
},
{
"path": "internal/utils.go",
"chars": 443,
"preview": "package internal\n\nimport (\n\t\"unicode\"\n)\n\n// IsntLetterOrNumber check if the give rune is not a letter nor a number\nfunc "
},
{
"path": "lint.mk",
"chars": 1459,
"preview": "# BEGIN: lint-install github.com/bmc-toolbox/bmclib/v2\n# http://github.com/tinkerbell/lint-install\n\n.PHONY: lint\nlint: _"
},
{
"path": "logging/logging.go",
"chars": 1070,
"preview": "package logging\n\nimport (\n\t\"os\"\n\n\t\"github.com/bombsimon/logrusr/v2\"\n\t\"github.com/go-logr/logr\"\n\t\"github.com/go-logr/zero"
},
{
"path": "option.go",
"chars": 5062,
"preview": "package bmclib\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/internal/http"
},
{
"path": "providers/asrockrack/asrockrack.go",
"chars": 4780,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2"
},
{
"path": "providers/asrockrack/asrockrack_test.go",
"chars": 1144,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"gopkg.in/go-playground/assert.v1\"\n)\n\nfunc TestHttpLo"
},
{
"path": "providers/asrockrack/firmware.go",
"chars": 9496,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/pkg/errors\"\n\n\t\"github.com/bmc-tool"
},
{
"path": "providers/asrockrack/firmware_update.md",
"chars": 1952,
"preview": "### BMC\n Flashing a BMC firmware seems to be a multi step process\n\n\n 1. PUT /api/maintenance/flash\n no payload (se"
},
{
"path": "providers/asrockrack/fixtures/E3C246D4I-NL/sensors.json",
"chars": 18956,
"preview": "[\n {\n \"id\": 1,\n \"sensor_number\": 1,\n \"name\": \"3VSB\",\n \"owner_id\": 32,\n \"owner_lun\""
},
{
"path": "providers/asrockrack/helpers.go",
"chars": 17655,
"preview": "package asrockrack\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/http/"
},
{
"path": "providers/asrockrack/helpers_test.go",
"chars": 2264,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"gopkg.in/go-playground/assert.v1\"\n)\n\nfunc Test_FirmwareInfo(t *tes"
},
{
"path": "providers/asrockrack/inventory.go",
"chars": 5321,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\n\t\"github.com/bmc-toolbox/common\"\n)\n\n// Inventory returns hardware and firmware "
},
{
"path": "providers/asrockrack/inventory_test.go",
"chars": 761,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGetInventory(t *te"
},
{
"path": "providers/asrockrack/mock_test.go",
"chars": 15633,
"preview": "package asrockrack\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\""
},
{
"path": "providers/asrockrack/power.go",
"chars": 3414,
"preview": "package asrockrack\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\tbmclibErrs \"github.com"
},
{
"path": "providers/asrockrack/user.go",
"chars": 5903,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/pkg/errors\"\n\n\tbmclibErrs \"github.com/bmc-toolbox"
},
{
"path": "providers/asrockrack/user_test.go",
"chars": 5005,
"preview": "package asrockrack\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net/http\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\n\t"
},
{
"path": "providers/dell/firmware.go",
"chars": 7020,
"preview": "package dell\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmcli"
},
{
"path": "providers/dell/firmware_test.go",
"chars": 2283,
"preview": "package dell\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestConvFirmwareTaskOem(t *testing.T) {"
},
{
"path": "providers/dell/fixtures/serviceroot.json",
"chars": 2191,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ServiceRoot.ServiceRoot\",\n \"@odata.id\": \"/redfish/v1\",\n \"@odata.typ"
},
{
"path": "providers/dell/fixtures/systems.json",
"chars": 446,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystemCollection.ComputerSystemCollection\",\n \"@odata.id\": \"/re"
},
{
"path": "providers/dell/fixtures/systems_embedded.1.json",
"chars": 17065,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n \"@odata.id\": \"/redfish/v1/Systems/System."
},
{
"path": "providers/dell/fixtures/systems_embedded_no_manufacturer.1.json",
"chars": 17056,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n \"@odata.id\": \"/redfish/v1/Systems/System."
},
{
"path": "providers/dell/fixtures/systems_embedded_not_dell.1.json",
"chars": 17062,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystem.ComputerSystem\",\n \"@odata.id\": \"/redfish/v1/Systems/System."
},
{
"path": "providers/dell/idrac.go",
"chars": 8197,
"preview": "package dell\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\""
},
{
"path": "providers/dell/idrac_test.go",
"chars": 5019,
"preview": "package dell\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"ne"
},
{
"path": "providers/homeassistant/homeassistant.go",
"chars": 7141,
"preview": "package homeassistant\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"gith"
},
{
"path": "providers/intelamt/intelamt.go",
"chars": 3927,
"preview": "package intelamt\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/providers\"\n\t\"github.com/g"
},
{
"path": "providers/intelamt/intelamt_test.go",
"chars": 5898,
"preview": "package intelamt\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/go-logr/logr\"\n\t\"github.com/google/go-cmp/cmp\"\n\t"
},
{
"path": "providers/ipmitool/ipmitool.go",
"chars": 4951,
"preview": "package ipmitool\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"strings\"\n\n\tbmclibErrs \"github.com/bmc-toolbox/bmclib/v2/errors\"\n\t\"gith"
},
{
"path": "providers/ipmitool/ipmitool_test.go",
"chars": 4094,
"preview": "package ipmitool\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/bmc-toolbox/bmcl"
},
{
"path": "providers/openbmc/firmware.go",
"chars": 3250,
"preview": "package openbmc\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/constants\"\n\t\"gi"
},
{
"path": "providers/openbmc/openbmc.go",
"chars": 4596,
"preview": "package openbmc\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/x509\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/bmc-toolbox/bmcl"
},
{
"path": "providers/providers.go",
"chars": 5138,
"preview": "package providers\n\nimport \"github.com/jacobweinstock/registrar\"\n\nconst (\n\t// FeaturePowerState represents the powerstate"
},
{
"path": "providers/redfish/fixtures/v1/dell/entries.json",
"chars": 1923,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#LogEntryCollection.LogEntryCollection\",\n \"@odata.id\": \"/redfish/v1/Man"
},
{
"path": "providers/redfish/fixtures/v1/dell/job_delete_ok.json",
"chars": 772,
"preview": "{\n \"@Message.ExtendedInfo\": [\n {\n \"Message\": \"Successfully Completed Request\",\n \"Message"
},
{
"path": "providers/redfish/fixtures/v1/dell/jobs.json",
"chars": 25768,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#DellJobCollection.DellJobCollection\",\n \"@odata.type\": \"#DellJobCollect"
},
{
"path": "providers/redfish/fixtures/v1/dell/logservices.json",
"chars": 486,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#LogServiceCollection.LogServiceCollection\",\n \"@odata.id\": \"/redfish/v1"
},
{
"path": "providers/redfish/fixtures/v1/dell/logservices.sel.json",
"chars": 775,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#LogService.LogService\",\n \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embe"
},
{
"path": "providers/redfish/fixtures/v1/dell/manager.idrac.embedded.1.json",
"chars": 397,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#Manager.Manager\",\n \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded.1"
},
{
"path": "providers/redfish/fixtures/v1/dell/managers.json",
"chars": 374,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ManagerCollection.ManagerCollection\",\n \"@odata.id\": \"/redfish/v1/Manag"
},
{
"path": "providers/redfish/fixtures/v1/dell/selentries/1.json",
"chars": 613,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#LogEntry.LogEntry\",\n \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded"
},
{
"path": "providers/redfish/fixtures/v1/dell/selentries/2.json",
"chars": 611,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#LogEntry.LogEntry\",\n \"@odata.id\": \"/redfish/v1/Managers/iDRAC.Embedded"
},
{
"path": "providers/redfish/fixtures/v1/serviceroot.json",
"chars": 2191,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ServiceRoot.ServiceRoot\",\n \"@odata.id\": \"/redfish/v1\",\n \"@odata.typ"
},
{
"path": "providers/redfish/fixtures/v1/systems.json",
"chars": 446,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#ComputerSystemCollection.ComputerSystemCollection\",\n \"@odata.id\": \"/re"
},
{
"path": "providers/redfish/fixtures/v1/updateservice.json",
"chars": 1771,
"preview": "{\n \"@odata.context\": \"/redfish/v1/$metadata#UpdateService.UpdateService\",\n \"@odata.id\": \"/redfish/v1/UpdateService"
},
{
"path": "providers/redfish/main_test.go",
"chars": 2956,
"preview": "package redfish\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github"
},
{
"path": "providers/redfish/redfish.go",
"chars": 7156,
"preview": "package redfish\n\nimport (\n\t\"context\"\n\t\"crypto/x509\"\n\t\"net/http\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/internal/httpclient\""
},
{
"path": "providers/redfish/sel.go",
"chars": 438,
"preview": "package redfish\n\nimport \"context\"\n\nfunc (c *Conn) ClearSystemEventLog(ctx context.Context) (err error) {\n\treturn c.redfi"
},
{
"path": "providers/redfish/sel_test.go",
"chars": 558,
"preview": "package redfish\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n// Write tests for GetSystemEv"
},
{
"path": "providers/redfish/user.go",
"chars": 3937,
"preview": "package redfish\n\nimport (\n\t\"context\"\n\n\t\"github.com/bmc-toolbox/bmclib/v2/internal\"\n\t\"github.com/pkg/errors\"\n\t\"github.com"
},
{
"path": "providers/rpc/doc.go",
"chars": 681,
"preview": "/*\nPackage rpc is a provider that defines an HTTP request/response contract for handling BMC interactions.\nIt allows use"
},
{
"path": "providers/rpc/experimental.go",
"chars": 584,
"preview": "package rpc\n\nimport (\n\t\"github.com/Jeffail/gabs/v2\"\n\t\"github.com/ghodss/yaml\"\n)\n\n// embedPayload will embed the RequestP"
},
{
"path": "providers/rpc/http.go",
"chars": 1922,
"preview": "package rpc\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\n// createRequest\nfun"
},
{
"path": "providers/rpc/http_test.go",
"chars": 4223,
"preview": "package rpc\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github."
},
{
"path": "providers/rpc/logging.go",
"chars": 1233,
"preview": "package rpc\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"net/http\"\n)\n\ntype requestDetails struct {\n\tBody RequestPayload `jso"
}
]
// ... and 19 more files (download for full content)
About this extraction
This page contains the full source code of the bmc-toolbox/bmclib GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 219 files (1.0 MB), approximately 300.2k tokens, and a symbol index with 1161 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.