Skip to content
Open
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
56 changes: 56 additions & 0 deletions cmd/local/subcmd/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/longhorn/cli/pkg/consts"
local "github.com/longhorn/cli/pkg/local/preflight"
localreplica "github.com/longhorn/cli/pkg/local/replica"
"github.com/longhorn/cli/pkg/types"
"github.com/longhorn/cli/pkg/utils"
)
Expand All @@ -22,6 +23,61 @@ func NewCmdCheck(globalOpts *types.GlobalCmdOptions) *cobra.Command {
utils.SetGlobalOptionsLocal(cmd, globalOpts)

cmd.AddCommand(newCmdCheckPreflight(globalOpts))
cmd.AddCommand(newCmdCheckReplica(globalOpts))

return cmd
}

func newCmdCheckReplica(globalOpts *types.GlobalCmdOptions) *cobra.Command {
var localChecker = localreplica.Checker{}

cmd := &cobra.Command{
Use: consts.SubCmdReplica,
Short: "Check Longhorn replica integrity",
Long: `This command checks the integrity of the snapshot chains in the Longhorn replica data directories.
It identifies broken snapshot chains, for example snapshots referencing a missing parent, disk files without metadata files, and metadata files without disk files.
The results are presented by the replica data directory names, not the actual Custom Resource (CR) names.

By default, this command checks all Longhorn replicas in the data directory.
You can narrow down the results by using the following options:
- --name: Specify the Longhorn replica data directory name to check a specific replica.
- --volume-name: Filter replicas by the volume they belong to.`,

PreRun: func(cmd *cobra.Command, args []string) {
localChecker.LogLevel = globalOpts.LogLevel

err := localChecker.Init()
if err != nil {
utils.CheckErr(errors.Wrap(err, "Failed to initialize replica checker"))
}
},

Run: func(cmd *cobra.Command, args []string) {
err := localChecker.Run()
if err != nil {
utils.CheckErr(errors.Wrap(err, "Failed to run replica checker"))
}

logrus.Info("Successfully checked replica integrity")
},

PostRun: func(cmd *cobra.Command, args []string) {
err := localChecker.Output()
if err != nil {
utils.CheckErr(errors.Wrap(err, "Failed to output replica checker collection"))
}

logrus.Info("Successfully output replica checker collection")
},
}

utils.SetGlobalOptionsLocal(cmd, globalOpts)

cmd.Flags().StringVar(&localChecker.CurrentNodeID, consts.CmdOptNodeId, os.Getenv(consts.EnvCurrentNodeID), "Current node ID.")
cmd.Flags().StringVarP(&localChecker.OutputFilePath, consts.CmdOptOutputFile, "o", os.Getenv(consts.EnvOutputFilePath), "Output the result to a file, default to stdout.")
cmd.Flags().StringVar(&localChecker.ReplicaName, consts.CmdOptName, os.Getenv(consts.EnvLonghornReplicaName), "Specify the name of the replica to check.")
cmd.Flags().StringVar(&localChecker.VolumeName, consts.CmdOptLonghornVolumeName, os.Getenv(consts.EnvLonghornVolumeName), "Specify the name of the volume to check its replicas.")
cmd.Flags().StringVar(&localChecker.LonghornDataDirectory, consts.CmdOptLonghornDataDirectory, os.Getenv(consts.EnvLonghornDataDirectory), "Specify the Longhorn data directory. If not provided, the default will be attempted, or it will fall back to the directory of longhorn-disk.cfg.")

return cmd
}
Expand Down
83 changes: 83 additions & 0 deletions cmd/remote/subcmd/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/longhorn/cli/pkg/consts"
"github.com/longhorn/cli/pkg/remote/preflight"
"github.com/longhorn/cli/pkg/remote/replica"
"github.com/longhorn/cli/pkg/types"
"github.com/longhorn/cli/pkg/utils"
)
Expand All @@ -20,6 +21,88 @@ func NewCmdCheck(globalOpts *types.GlobalCmdOptions) *cobra.Command {
utils.SetGlobalOptionsRemote(cmd, globalOpts)

cmd.AddCommand(newCmdCheckPreflight(globalOpts))
cmd.AddCommand(newCmdCheckReplica(globalOpts))

return cmd
}

func newCmdCheckReplica(globalOpts *types.GlobalCmdOptions) *cobra.Command {
var replicaChecker = replica.Checker{}

cmd := &cobra.Command{
Use: consts.SubCmdReplica,
Short: "Check Longhorn replica integrity",
Long: `This command checks the integrity of the snapshot chains in the Longhorn replica data directories on each node.
It identifies broken snapshot chains, for example snapshots referencing a missing parent, disk files without metadata files, and metadata files without disk files.
The results are presented by the replica data directory names, not the actual Custom Resource (CR) names.

By default, this command checks all Longhorn replicas in the data directory.
You can narrow down the results by using the following options:
- --name: Specify the Longhorn replica data directory name to check a specific replica.
- --volume-name: Filter replicas by the volume they belong to.`,
Example: `$ longhornctl check replica
INFO[2024-07-16T17:23:47+08:00] Initializing replica checker
INFO[2024-07-16T17:23:47+08:00] Cleaning up replica checker
INFO[2024-07-16T17:23:47+08:00] Running replica checker
INFO[2024-07-16T17:23:51+08:00] Retrieved replica check results:
replicas:
pvc-48a6457d-585e-423b-b530-bbc68a5f948a-0e2603a7:
- node: ip-10-0-2-123
directory: /var/lib/longhorn/replicas/pvc-48a6457d-585e-423b-b530-bbc68a5f948a-0e2603a7
volumeName: pvc-48a6457d-585e-423b-b530-bbc68a5f948a
snapshotChain:
- volume-head-001.img
- volume-snap-40b3b028-b3b3-4a35-a806-8bea77f27c00.img
errors:
- 'broken snapshot chain: disk volume-snap-40b3b028-b3b3-4a35-a806-8bea77f27c00.img references parent volume-snap-6f244bbe-2857-46e4-92e2-eb1e16a63ba1.img, but the parent metadata file is missing'
INFO[2024-07-16T17:23:51+08:00] Cleaning up replica checker
INFO[2024-07-16T17:23:51+08:00] Completed replica checker`,

PreRun: func(cmd *cobra.Command, args []string) {
replicaChecker.Image = globalOpts.Image
replicaChecker.ImageRegistry = globalOpts.ImageRegistry
replicaChecker.ImagePullSecret = globalOpts.ImagePullSecret
replicaChecker.KubeConfigPath = globalOpts.KubeConfigPath
replicaChecker.NodeSelector = globalOpts.NodeSelector
replicaChecker.Tolerations = globalOpts.Tolerations
replicaChecker.Namespace = globalOpts.Namespace

logrus.Info("Initializing replica checker")
if err := replicaChecker.Init(); err != nil {
utils.CheckErr(errors.Wrap(err, "Failed to initialize replica checker"))
}

logrus.Info("Cleaning up replica checker")
if err := replicaChecker.Cleanup(); err != nil {
utils.CheckErr(errors.Wrapf(err, "Failed to cleanup replica checker"))
}
},

Run: func(cmd *cobra.Command, args []string) {
logrus.Info("Running replica checker")
output, err := replicaChecker.Run()
if err != nil {
utils.CheckErr(errors.Wrap(err, "Failed to run replica checker"))
}

logrus.Infof("Retrieved replica check results:\n %v", output)
},

PostRun: func(cmd *cobra.Command, args []string) {
logrus.Info("Cleaning up replica checker")
if err := replicaChecker.Cleanup(); err != nil {
utils.CheckErr(errors.Wrapf(err, "Failed to cleanup replica checker"))
}

logrus.Info("Completed replica checker")
},
}

utils.SetGlobalOptionsRemote(cmd, globalOpts)

cmd.Flags().StringVar(&replicaChecker.ReplicaName, consts.CmdOptName, "", "Specify the name of the replica to check.")
cmd.Flags().StringVar(&replicaChecker.VolumeName, consts.CmdOptLonghornVolumeName, "", "Specify the name of the volume to check its replicas.")
cmd.Flags().StringVar(&replicaChecker.LonghornDataDirectory, consts.CmdOptLonghornDataDirectory, "/var/lib/longhorn", "Specify the Longhorn data directory. If not provided, the default will be attempted, or it will fall back to the directory of longhorn-disk.cfg.")

return cmd
}
Expand Down
3 changes: 2 additions & 1 deletion docs/longhornctl_check.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ Longhorn checking operations

* [longhornctl](longhornctl.md) - Command-line interface for Longhorn.
* [longhornctl check preflight](longhornctl_check_preflight.md) - Run a preflight check for Longhorn
* [longhornctl check replica](longhornctl_check_replica.md) - Check Longhorn replica integrity

###### Auto generated by spf13/cobra on 6-Jul-2026
###### Auto generated by spf13/cobra on 20-Jul-2026
68 changes: 68 additions & 0 deletions docs/longhornctl_check_replica.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
## longhornctl check replica

Check Longhorn replica integrity

### Synopsis

This command checks the integrity of the snapshot chains in the Longhorn replica data directories on each node.
It identifies broken snapshot chains, for example snapshots referencing a missing parent, disk files without metadata files, and metadata files without disk files.
The results are presented by the replica data directory names, not the actual Custom Resource (CR) names.

By default, this command checks all Longhorn replicas in the data directory.
You can narrow down the results by using the following options:
- --name: Specify the Longhorn replica data directory name to check a specific replica.
- --volume-name: Filter replicas by the volume they belong to.

```
longhornctl check replica [flags]
```

### Examples

```
$ longhornctl check replica
INFO[2024-07-16T17:23:47+08:00] Initializing replica checker
INFO[2024-07-16T17:23:47+08:00] Cleaning up replica checker
INFO[2024-07-16T17:23:47+08:00] Running replica checker
INFO[2024-07-16T17:23:51+08:00] Retrieved replica check results:
replicas:
pvc-48a6457d-585e-423b-b530-bbc68a5f948a-0e2603a7:
- node: ip-10-0-2-123
directory: /var/lib/longhorn/replicas/pvc-48a6457d-585e-423b-b530-bbc68a5f948a-0e2603a7
volumeName: pvc-48a6457d-585e-423b-b530-bbc68a5f948a
snapshotChain:
- volume-head-001.img
- volume-snap-40b3b028-b3b3-4a35-a806-8bea77f27c00.img
errors:
- 'broken snapshot chain: disk volume-snap-40b3b028-b3b3-4a35-a806-8bea77f27c00.img references parent volume-snap-6f244bbe-2857-46e4-92e2-eb1e16a63ba1.img, but the parent metadata file is missing'
INFO[2024-07-16T17:23:51+08:00] Cleaning up replica checker
INFO[2024-07-16T17:23:51+08:00] Completed replica checker
```

### Options

```
--data-dir string Specify the Longhorn data directory. If not provided, the default will be attempted, or it will fall back to the directory of longhorn-disk.cfg. (default "/var/lib/longhorn")
-h, --help help for replica
--image string Image containing longhornctl-local (default "longhornio/longhorn-cli:v1.13.0-dev")
--image-pull-secret string Secret with registry credentials for pulling images
--image-registry string Registry to apply to all images (CLI, engine, pause, BCI, etc.), replacing any registry already specified in those images.
--kubeconfig string Kubernetes config (kubeconfig) path
-l, --log-level string Log level (default "info")
--name string Specify the name of the replica to check.
--namespace string The namespace to run DaemonSet pods. (default "longhorn-system")
--node-selector string Comma-separated list of key=value pairs to match against node labels, selecting the nodes the DaemonSet will run on (e.g. env=prod,zone=us-west).
--volume-name string Specify the name of the volume to check its replicas.
```

### Options inherited from parent commands

```
--tolerations string Semicolon-separated list of tolerations for DaemonSet pods (e.g. key=value:NoSchedule;:NoExecute).
```

### SEE ALSO

* [longhornctl check](longhornctl_check.md) - Longhorn checking operations

###### Auto generated by spf13/cobra on 20-Jul-2026
1 change: 1 addition & 0 deletions pkg/consts/replica.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package consts

const (
AppNameReplicaChecker = "longhorn-replica-checker"
AppNameReplicaExporter = "longhorn-replica-exporter"
AppNameReplicaGetter = "longhorn-replica-getter"
)
Loading