Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Longhorn toolbox CLI #14

Merged
merged 7 commits into from
Jul 11, 2024
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
2 changes: 1 addition & 1 deletion Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ENV ARCH=${DAPPER_HOST_ARCH}

ENV DAPPER_RUN_ARGS --privileged
ENV DAPPER_ENV REPO TAG DRONE_TAG
ENV DAPPER_SOURCE /longhorn-preflight
ENV DAPPER_SOURCE /cli
ENV DAPPER_OUTPUT ./bin ./spdk coverage.out
ENV DAPPER_DOCKER_SOCKET true

Expand Down
59 changes: 29 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,43 @@
# Longhorn Preflight
# Longhorn Commandline Interface (longhornctl)

`longhorn-preflight` helps install, configure and check the prerequisites for Longhorn system.
This repository contains the source code for `longhornctl`, a CLI (command-line interface) designed to simplify Longhorn manual operations.

## Install
## What Can You Do With `longhornctl`?

### Deploy
- Install and verify prelight requirements.
- Execute one-time Longhorn operations.
- Gain inside into your Longhorn system.

Users can create `longhorn-preflight` DaemonSet for installing and configuring the prerequisites and the environment.
## Install `longhornctl`

```
# kubectl -f deploy/install.yaml
```
### Run From Container Image

### Tweak the Options
`To be updated`

#### General Options
### Using curl
c3y1huang marked this conversation as resolved.
Show resolved Hide resolved

- `UPDATE_PACKAGE_LIST`: Update package list before install required packages.
`To be updated`

#### SPDK Specific Options
### Build From Source

- `ENABLE_SPDK`: Enable installation of required packages, modules and setup.
- `HUGEMEM`: Hugepage size in MiB for SPDK.
- `PCI_ALLOWED`: Whitespace separated list of PCI devices. By default, block all PCI devices use a non-valid address.
- `DRIVER_OVERRIDE`: Bind devices to the given user space driver.
1. Clone repository
```bash
git clone https://github.com/longhorn/cli.git
```
1. Build the `longhornctl` binary
```bash
cd cli
make
```
> **Note:** This process will generate two binaries:
> - `longhornctl`: A command-line interface for remote Longhorn operations, designed to be run outside the Kubernetes cluster. It executes `longhornctl-local` for operations within the cluster.
> - `longhornctl-local`: A command-line interface to be used within a DaemonSet pod inside the Kubernetes cluster, handling in-cluster and host operations.
1. After the build process completes, find the `longhornctl` binary in the `./bin` directory.

c3y1huang marked this conversation as resolved.
Show resolved Hide resolved
## Check
## Getting Started

### Deploy
To begin, run `longhornctl --help` to access a list of available commands and options.
c3y1huang marked this conversation as resolved.
Show resolved Hide resolved

Users can create `longhorn-preflight` DaemonSet for checking the prerequisites and the environment.
### Command Reference

```
# kubectl -f deploy/check.yaml
```

### Tweak the Options

#### SPDK Specific Options

- `ENABLE_SPDK`: Enable installation of required packages, modules and setup.
- `HUGEMEM`: Hugepage size in MiB for SPDK.
- `UIO_DRIVER`: Userspace IO driver.
`To be updated`
50 changes: 0 additions & 50 deletions cmd/app/check.go

This file was deleted.

50 changes: 0 additions & 50 deletions cmd/app/install.go

This file was deleted.

73 changes: 73 additions & 0 deletions cmd/local/longhornctl-local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

import (
"os"

"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"k8s.io/kubectl/pkg/util/templates"

localsubcmd "github.com/longhorn/cli/cmd/local/subcmd"
remotesubcmd "github.com/longhorn/cli/cmd/remote/subcmd"
"github.com/longhorn/cli/pkg/consts"
"github.com/longhorn/cli/pkg/types"
"github.com/longhorn/cli/pkg/utils"
)

func main() {
if err := newCmdLonghornctlLocal().Execute(); err != nil {
logrus.WithError(err).Fatal("Failed to execute command")
os.Exit(1)
}
}

func newCmdLonghornctlLocal() *cobra.Command {
globalOpts := &types.GlobalCmdOptions{}

cmd := &cobra.Command{
Use: consts.CmdLonghornctlLocal,
Short: "Longhorn commandline interface.",
Long: "CLI (local) for troubleshooting and operations to be used in the Kubernetes cluster.",
Comment on lines +30 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: tried to undertand the longhornctl-local and longhornctl. The naming is a bit confusing. We can find better names later.

PersistentPreRun: func(cmd *cobra.Command, args []string) {
c3y1huang marked this conversation as resolved.
Show resolved Hide resolved
err := utils.SetLog(globalOpts.LogLevel)
if err != nil {
logrus.WithError(err).Warn("Failed to set log level")
}
},
}

cmd.CompletionOptions.HiddenDefaultCmd = true

cmd.PersistentFlags().StringVarP(&globalOpts.LogLevel, consts.CmdOptLogLevel, "l", "info", "log level (trace, debug, info, warn, error, fatal, panic)")

groups := templates.CommandGroups{
{
Message: "Install And Uninstall Commands:",
Commands: []*cobra.Command{
localsubcmd.NewCmdInstall(globalOpts),
},
},
{
Message: "Operation Commands:",
Commands: []*cobra.Command{
localsubcmd.NewCmdTrim(globalOpts),
},
},
{
Message: "Troubleshoot Commands:",
Commands: []*cobra.Command{
localsubcmd.NewCmdCheck(globalOpts),
localsubcmd.NewCmdGet(globalOpts),
},
},
}
groups.Add(cmd)

cmd.AddCommand(remotesubcmd.NewCmdGlobalOptions())

filters := []string{"options"}
templates.ActsAsRootCommand(cmd, filters, groups...)

return cmd
}
71 changes: 71 additions & 0 deletions cmd/local/subcmd/check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package cmd

import (
"os"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/longhorn/cli/pkg/consts"
local "github.com/longhorn/cli/pkg/local/preflight"
"github.com/longhorn/cli/pkg/types"
"github.com/longhorn/cli/pkg/utils"
)

func NewCmdCheck(globalOpts *types.GlobalCmdOptions) *cobra.Command {
cmd := &cobra.Command{
Use: consts.SubCmdCheck,
Short: "Longhorn checking operations",
}

utils.SetGlobalOptionsLocal(cmd, globalOpts)

cmd.AddCommand(newCmdCheckPreflight(globalOpts))

return cmd
}

func newCmdCheckPreflight(globalOpts *types.GlobalCmdOptions) *cobra.Command {
var localChecker = local.Checker{}
c3y1huang marked this conversation as resolved.
Show resolved Hide resolved

cmd := &cobra.Command{
Use: consts.SubCmdPreflight,
Short: "Check preflight environment",
Long: `This command verifies your Kubernetes cluster environment. It performs a series of checks to ensure your cluster meets the requirements for Longhorn to function properly.
These checks can help to identify issues that might prevent Longhorn from functioning properly.`,

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

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

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

logrus.Info("Successfully checked preflight environment")
},

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

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

utils.SetGlobalOptionsLocal(cmd, globalOpts)

cmd.Flags().StringVarP(&localChecker.OutputFilePath, consts.CmdOptOutputFile, "o", os.Getenv(consts.EnvOutputFilePath), "Output the result to a file, default to stdout.")
cmd.Flags().BoolVar(&localChecker.EnableSpdk, consts.CmdOptEnableSpdk, utils.ConvertStringToTypeOrDefault(os.Getenv(consts.EnvEnableSpdk), false), "Enable checking of SPDK required packages, modules, and setup.")
cmd.Flags().IntVar(&localChecker.HugePageSize, consts.CmdOptHugePageSize, utils.ConvertStringToTypeOrDefault(os.Getenv(consts.EnvHugePageSize), 1024), "Specify the huge page size in MiB for SPDK.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is iSCS and NFS client? I would recommend highlighting them and make them by default.

In the future, probably can exclusively enable one of them.

EnableSPDK need to depend on if HugePageSize is set as well.

Copy link
Contributor Author

@c3y1huang c3y1huang Jul 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is iSCS and NFS client? I would recommend highlighting them and make them by default.

Both will be checked, there is no option to enable or disable them individually. The results will be outputted in detail.

ip-10-0-2-10:
  info:
  - Service iscsid is running
  - NFS4 is supported
  - Package nfs-client is installed
  - Package open-iscsi is installed
  - CPU instruction set sse4_2 is supported
  - HugePages is enabled
  - Module nvme_tcp is loaded
  - Module uio_pci_generic is loaded
ip-10-0-2-15:
  info:
  - Service iscsid is running
  - NFS4 is supported
  - Package nfs-client is installed
  - Package open-iscsi is installed
  - CPU instruction set sse4_2 is supported
  - HugePages is enabled
  - Module nvme_tcp is loaded
  - Module uio_pci_generic is loaded
ip-10-0-2-167:
  error:
  - Neither iscsid.service nor iscsid.socket is running
  info:
  - NFS4 is supported
  - Package nfs-client is installed
  - Package open-iscsi is installed
  - CPU instruction set sse4_2 is supported
  - HugePages is enabled
  - Module nvme_tcp is loaded
  - Module uio_pci_generic is loaded 

In the future, probably can exclusively enable one of them.

I think the output is clear enough to indicate whether the individual items meet the requirement. Adding extra options might complicate the process for users. Is there any benefit to having separate flags for enabling the checking of iSCSI and NFS client?

EnableSPDK need to depend on if HugePageSize is set as well.

The flags have been carried over from the current implementation. I don't have much experience with the v2 engine dependency check, so I suggest enhancing it in a separate PR specific to the v2 engine. @derekbit @innobead , what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me!

cmd.Flags().StringVar(&localChecker.UioDriver, consts.CmdOptUioDriver, os.Getenv(consts.EnvUioDriver), "User space I/O driver for SPDK.")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AIO instead of UIO?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return cmd
}
Loading