Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
"abandonments:recommended"
],

"env": {
"GOPRIVATE": "github.com/scality/*"
},

"packageRules": [
{
"matchDatasources": ["go"],
Expand Down
3 changes: 0 additions & 3 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,6 @@ formatters:
settings:
gofumpt:
extra-rules: true
goimports:
local-prefixes:
- github.com/scality/artesca
exclusions:
generated: lax
paths:
Expand Down
70 changes: 70 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Contributing

Thank you for your interest in contributing to RAIDmgmt! Here are some
guidelines to help you get started.

## Code of Conduct

Be respectful and constructive in all interactions. We expect contributors to
communicate professionally, provide helpful feedback, and work collaboratively
toward the shared goals of the project.

## Getting Started

1. Fork the repository and clone your fork.
2. Make sure you have Go 1.25+ and [golangci-lint](https://golangci-lint.run/)
installed.
3. Run `make all` to verify that linting and tests pass before making changes.

## Making Changes

1. Create a branch for your work.
2. Keep commits focused -- one logical change per commit.
3. Follow the existing code style. The project uses `golangci-lint` with the
configuration in `.golangci.yaml`.
4. Add or update tests for any changed behavior.
5. Run `make all` before submitting your changes.

## Testing

- All new code must have accompanying unit tests.
- Tests should go in `_test.go` files alongside the code they test.
- Use testdata fixtures for CLI output parsing tests (see
`pkg/implementation/raidcontroller/megaraid/testdata/` for examples).
- Run the full test suite with `make tests` and ensure all tests pass.
- Run `make lint` to verify your code passes all linter checks.

## Documentation

- Update the README.md or DESIGN.md if your change affects the public API,
architecture, or supported controllers.
- Document exported types and functions with Go doc comments.
- If adding a new adapter, document any limitations (unsupported operations)
in DESIGN.md.

## Adding a New RAID Controller

The library is designed to be extended with new controllers. To add one:

1. Create a new package under `pkg/implementation/` for any low-level CLI
interactions (command runners, getters, managers).
2. Implement the port interfaces defined in `pkg/domain/ports/raidcontroller.go`.
If your controller does not support a given operation, return
`ports.ErrFunctionNotSupportedByImplementation`.
3. Create a composite adapter under `pkg/implementation/raidcontroller/` that
wires the individual implementations together (see `rhel8.go` or
`smartarray.go` for examples).
4. Add unit tests with testdata fixtures.

## Pull Requests

1. Open a pull request against the `main` branch.
2. Describe what your change does and why.
3. Make sure CI checks pass (lint + tests).
4. At least one maintainer review is required before merging.

## Reporting Issues

Open a [GitHub issue](https://github.com/scality/raidmgmt/issues) with a clear
description of the problem or feature request. Include steps to reproduce if
applicable.
161 changes: 161 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Design

## Scope

This library abstracts RAID configuration and provides a unified interface to
interact with various hardware RAID controllers and software RAID setups.

It does **not** contain any higher-level decision logic about _what_ RAID
operations should be performed in specific scenarios. It only provides the
building blocks to execute them.

## Architecture

The library follows [Hexagonal Architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software))
with three main concepts:

- **Entity** -- A representation of a physical or logical resource.
- **Port** -- An abstract interface describing operations on resources.
- **Adapter** -- A concrete implementation of a Port for a specific controller type.

### Entities

#### `RAIDController`

Represents a RAID controller card.

```go
type RAIDController struct {
*Metadata

Name string // Name of the RAID controller card
Serial string // Serial number of the RAID controller card
IsJBODSupported bool // Can the controller be set in JBOD mode
IsJBODEnabled bool // Is the controller currently in JBOD mode
}
```

#### `PhysicalDrive`

Represents a physical drive (disk).

```go
type DiskType uint8 // Unknown, HDD, SSD, NVMe
type PDStatus uint8 // Unknown, Used, UnassignedGood, UnassignedBad, Failed

type Slot struct {
Port string // Port number (if available)
Enclosure string // Enclosure number (if available)
Bay string // Bay number (if available)
}

type PhysicalDrive struct {
*Metadata

Slot *Slot
Vendor string
Model string
Serial string
WWN string // World Wide Name
Size uint64 // Size in bytes
Type DiskType // HDD, SSD, NVMe
JBOD bool // Is the disk in JBOD mode
Status PDStatus
Reason string // Reason for the current status
DevicePath string // e.g. /dev/sda
PermanentPath string // e.g. /dev/disk/by-id/...
}
```

#### `LogicalVolume`

Represents a logical volume (RAID array).

```go
type RAIDLevel uint8 // Unknown, RAID0, RAID1, RAID10
type LVStatus uint8 // Unknown, Optimal, Degraded, Failed

type CacheOptions struct {
ReadPolicy ReadPolicy // ReadAhead, NoReadAhead
WritePolicy WritePolicy // WriteBack, WriteThrough, AlwaysWriteBack
IOPolicy IOPolicy // Direct, Cached
}

type LogicalVolume struct {
*Metadata

PermanentPath string
DevicePath string
RAIDLevel RAIDLevel
PDrivesMetadata []*physicaldrive.Metadata
CacheOptions *CacheOptions
Status LVStatus
Reason string
Size uint64
}
```

### Ports

The main port is `RAIDController`, which composes several fine-grained interfaces:

| Interface | Responsibility |
|---|---|
| `ControllersGetter` | List and get RAID controllers |
| `PhysicalDrivesGetter` | List and get physical drives |
| `LogicalVolumesGetter` | List and get logical volumes |
| `LogicalVolumesManager` | Create, delete, and modify logical volumes |
| `LVCacheSetter` | Set cache options on logical volumes |
| `JBODSetter` | Enable/disable JBOD mode on physical drives |
| `Blinker` | Start/stop drive identification blinking |

Not all adapters support every operation. Unsupported operations return
`ErrFunctionNotSupportedByImplementation`.

### Adapters

#### MegaRAID / PERC

Adapter for Broadcom MegaRAID and Dell PERC controllers. Interacts with
hardware via `storcli`/`perccli`, which provides JSON output for easy parsing.

Supports all port operations: controller listing, physical drives, logical
volumes (CRUD), cache options, JBOD, and drive blinking.

> **Note:** The current MegaRAID implementation (`pkg/implementation/raidcontroller/megaraid/`)
> is a monolithic package that predates the decomposed architecture used by the
> Smart Array and RHEL8 adapters. It is planned for refactoring to follow the
> same pattern -- splitting into separate `commandrunner`, `controllergetter`,
> `physicaldrivegetter`, `logicalvolumegetter`, and `logicalvolumemanager`
> packages, and composing them in a top-level adapter.

#### Smart Array

Adapter for HPE Smart Array controllers. Interacts with hardware via `ssacli`.
Unlike `storcli`, this tool does not support JSON output, so responses are
parsed using regular expressions.

Supports all port operations.

#### Software RAID (RHEL8)

Adapter for `mdadm`-based software RAID on RHEL8-family systems.

Uses `mdadm`, `lsblk`, `udevadm`, and `smartctl` to gather information and
manage arrays.

This adapter has the following limitations compared to hardware RAID:

- No cache options.
- No drive blinking.
- No RAID 0 single-disk arrays.
- No JBOD mode.
- The `RAIDController` entity is not applicable (there is no hardware controller).
- Partitions may be used as members of an array. Each partition is represented
as a `PhysicalDrive`, but this library does not manage partitions themselves.

## Core Service

The `core.RAIDController` wraps any adapter and adds input validation before
delegating to the underlying implementation. This is the recommended entry
point for consumers of the library.
Loading