Skip to content

Commit

Permalink
Add progress UI for drive initialization command
Browse files Browse the repository at this point in the history
  • Loading branch information
Praveenrajmani committed Feb 3, 2023
1 parent 86f7723 commit 6a9f7bd
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 12 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ directpv
kubectl-directpv
!kubectl-directpv/
vdb.xml
drives.yaml
61 changes: 54 additions & 7 deletions cmd/kubectl-directpv/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ import (
"fmt"
"os"
"strings"
"sync"
"time"

"github.com/charmbracelet/bubbles/progress"
tea "github.com/charmbracelet/bubbletea"
"github.com/fatih/color"
"github.com/google/uuid"
"github.com/jedib0t/go-pretty/v6/table"
Expand All @@ -44,7 +47,10 @@ type initResult struct {
devices []types.InitDeviceResult
}

var initRequestListTimeout = 2 * time.Minute
var (
initRequestListTimeout = 2 * time.Minute
tick = "✔"
)

var initCmd = &cobra.Command{
Use: "init drives.yaml",
Expand Down Expand Up @@ -110,6 +116,9 @@ func toInitRequestObjects(config *InitConfig, requestID string) (initRequests []
}

func showResults(results []initResult) {
if len(results) == 0 {
return
}
writer := newTableWriter(
table.Row{
"REQUEST_ID",
Expand Down Expand Up @@ -164,14 +173,22 @@ func showResults(results []initResult) {
writer.Render()
}

func initDevices(ctx context.Context, initRequests []types.InitRequest, requestID string) (results []initResult, err error) {
var totalReqCount int
func initDevices(ctx context.Context, initRequests []types.InitRequest, requestID string, teaProgram *tea.Program) (results []initResult, err error) {
totalReqCount := len(initRequests)
totalTasks := totalReqCount * 2
var completedTasks int
for i := range initRequests {
_, err := client.InitRequestClient().Create(ctx, &initRequests[i], metav1.CreateOptions{TypeMeta: types.NewInitRequestTypeMeta()})
initReq, err := client.InitRequestClient().Create(ctx, &initRequests[i], metav1.CreateOptions{TypeMeta: types.NewInitRequestTypeMeta()})
if err != nil {
return nil, err
}
totalReqCount++
if teaProgram != nil {
completedTasks++
teaProgram.Send(progressNotification{
log: fmt.Sprintf("Created initialization request '%s' for node '%v' %s", initReq.Name, initReq.GetNodeID(), tick),
percent: float64(completedTasks) / float64(totalTasks),
})
}
}
ctx, cancel := context.WithTimeout(ctx, initRequestListTimeout)
defer cancel()
Expand Down Expand Up @@ -205,6 +222,13 @@ func initDevices(ctx context.Context, initRequests []types.InitRequest, requestI
devices: initReq.Status.Results,
failed: initReq.Status.Status == directpvtypes.InitStatusError,
})
if teaProgram != nil {
completedTasks++
teaProgram.Send(progressNotification{
log: fmt.Sprintf("Processed initialization request '%s' for node '%v' %s", initReq.Name, initReq.GetNodeID(), tick),
percent: float64(completedTasks) / float64(totalTasks),
})
}
}
if len(results) >= totalReqCount {
return
Expand Down Expand Up @@ -249,10 +273,33 @@ func initMain(ctx context.Context, inputFile string) {
LabelSelector: directpvtypes.ToLabelSelector(labelMap),
})
}()
results, err := initDevices(ctx, initRequests, requestID)
if err != nil {
var teaProgram *tea.Program
var wg sync.WaitGroup
if !quietFlag {
m := progressModel{
model: progress.New(progress.WithDefaultGradient()),
}
teaProgram = tea.NewProgram(m)
wg.Add(1)
go func() {
defer wg.Done()
if _, err := teaProgram.Run(); err != nil {
fmt.Println("error running program:", err)
os.Exit(1)
}
}()
}
results, err := initDevices(ctx, initRequests, requestID, teaProgram)
if err != nil && quietFlag {
utils.Eprintf(quietFlag, true, "%v\n", err)
os.Exit(1)
}
if teaProgram != nil {
teaProgram.Send(progressNotification{
done: true,
err: err,
})
wg.Wait()
}
showResults(results)
}
7 changes: 5 additions & 2 deletions cmd/kubectl-directpv/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ var installCmd = &cobra.Command{
$ kubectl {PLUGIN_NAME} install -o yaml > directpv-install.yaml
6. Install DirectPV with apparmor profile
$ kubectl {PLUGIN_NAME} install --apparmor-profile apparmor.json`,
$ kubectl {PLUGIN_NAME} install --apparmor-profile directpv
7. Install DirectPV with seccomp profile
$ kubectl {PLUGIN_NAME} install --seccomp-profile profiles/seccomp.json`,
`{PLUGIN_NAME}`,
consts.AppName,
),
Expand Down Expand Up @@ -290,7 +293,7 @@ func installMain(ctx context.Context) {
var wg sync.WaitGroup
if dryRunPrinter == nil && !quietFlag {
m := progressModel{
model: progress.New(progress.WithGradient("#FFFFFF", "#FFFFFF")),
model: progress.New(progress.WithDefaultGradient()),
}
teaProgram := tea.NewProgram(m)
wg.Add(1)
Expand Down
9 changes: 7 additions & 2 deletions cmd/kubectl-directpv/progress_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,15 @@ func (m progressModel) View() (str string) {
pad := strings.Repeat(" ", padding)
str = "\n" + pad + m.model.View() + "\n\n"
if !m.done {
str += pad + fmt.Sprintf("%s \n\n", m.message)
if m.message != "" {
str += pad + fmt.Sprintf("%s \n\n", m.message)
}
}
for i := range m.logs {
str += pad + color.HiYellowString(fmt.Sprintf("%s \n\n", m.logs[i]))
str += pad + color.HiYellowString(fmt.Sprintf("%s \n", m.logs[i]))
if i == len(m.logs)-1 {
str += "\n"
}
}
if m.err != nil {
str += pad + color.HiRedString("Error; %s \n\n", m.err.Error())
Expand Down
2 changes: 1 addition & 1 deletion functests/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ function add_drives() {
rm "${config_file}"
return 1
fi
if ! echo Yes | "${DIRECTPV_CLIENT}" init "${config_file}" > /tmp/.output 2>&1; then
if ! echo Yes | "${DIRECTPV_CLIENT}" init --quiet "${config_file}" > /tmp/.output 2>&1; then
cat /tmp/.output
echo "$ME: error: failed to initialize the drives"
rm "${config_file}"
Expand Down

0 comments on commit 6a9f7bd

Please sign in to comment.