Skip to content

Commit

Permalink
Merge pull request #4 from galal-hussein/add_migrate_all
Browse files Browse the repository at this point in the history
Add migrate all in interactive mode
  • Loading branch information
galal-hussein authored Feb 21, 2024
2 parents b1a2cde + d736a40 commit 4811166
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 44 deletions.
5 changes: 2 additions & 3 deletions cli/cmds/interactive/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func NewCommand() *cli.Command {

func migrate(clx *cli.Context) error {
ctx := context.Background()

cmds.Spinner.Prefix = fmt.Sprintf("initiating source [%s] and target [%s] clusters objects.. ", source, target)
cmds.Spinner.Start()
restConfig, err := clientcmd.BuildConfigFromFlags("", cmds.Kubeconfig)
if err != nil {
return err
Expand Down Expand Up @@ -100,8 +101,6 @@ func migrate(clx *cli.Context) error {
Client: tcClient,
}

cmds.Spinner.Prefix = fmt.Sprintf("initiating source [%s] and target [%s] clusters objects.. ", sc.Obj.Spec.DisplayName, tc.Obj.Spec.DisplayName)
cmds.Spinner.Start()
if err := sc.Populate(ctx, cl); err != nil {
return err
}
Expand Down
8 changes: 4 additions & 4 deletions cli/cmds/migrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"galal-hussein/cattle-drive/cli/cmds"
"galal-hussein/cattle-drive/pkg/client"
"galal-hussein/cattle-drive/pkg/cluster"
"os"

v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -44,7 +45,8 @@ func NewCommand() *cli.Command {

func migrate(clx *cli.Context) error {
ctx := context.Background()

cmds.Spinner.Prefix = fmt.Sprintf("initiating source [%s] and target [%s] clusters objects.. ", source, target)
cmds.Spinner.Start()
restConfig, err := clientcmd.BuildConfigFromFlags("", cmds.Kubeconfig)
if err != nil {
return err
Expand Down Expand Up @@ -98,8 +100,6 @@ func migrate(clx *cli.Context) error {
Obj: targetCluster,
Client: tcClient,
}
cmds.Spinner.Prefix = fmt.Sprintf("initiating source [%s] and target [%s] clusters objects.. ", sc.Obj.Spec.DisplayName, tc.Obj.Spec.DisplayName)
cmds.Spinner.Start()
if err := sc.Populate(ctx, cl); err != nil {
return err
}
Expand All @@ -110,5 +110,5 @@ func migrate(clx *cli.Context) error {
return err
}
cmds.Spinner.Stop()
return sc.Migrate(ctx, cl, tc)
return sc.Migrate(ctx, cl, tc, os.Stdout)
}
5 changes: 2 additions & 3 deletions cli/cmds/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ func NewCommand() *cli.Command {

func status(clx *cli.Context) error {
ctx := context.Background()

cmds.Spinner.Prefix = fmt.Sprintf("initiating source [%s] and target [%s] clusters objects.. ", source, target)
cmds.Spinner.Start()
restConfig, err := clientcmd.BuildConfigFromFlags("", cmds.Kubeconfig)
if err != nil {
return err
Expand Down Expand Up @@ -98,8 +99,6 @@ func status(clx *cli.Context) error {
Obj: targetCluster,
Client: tcClient,
}
cmds.Spinner.Prefix = fmt.Sprintf("initiating source [%s] and target [%s] clusters objects.. ", sc.Obj.Spec.DisplayName, tc.Obj.Spec.DisplayName)
cmds.Spinner.Start()
if err := sc.Populate(ctx, cl); err != nil {
return err
}
Expand Down
25 changes: 13 additions & 12 deletions pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"galal-hussein/cattle-drive/pkg/client"
"io"
"reflect"

v1catalog "github.com/rancher/rancher/pkg/apis/catalog.cattle.io/v1"
Expand Down Expand Up @@ -230,60 +231,60 @@ func (c *Cluster) Status(ctx context.Context, client *client.Clients) error {
return nil
}

func (c *Cluster) Migrate(ctx context.Context, client *client.Clients, tc *Cluster) error {
fmt.Printf("Migrating Objects from cluster [%s] to cluster [%s]:\n", c.Obj.Spec.DisplayName, tc.Obj.Spec.DisplayName)
func (c *Cluster) Migrate(ctx context.Context, client *client.Clients, tc *Cluster, w io.Writer) error {
fmt.Fprintf(w, "Migrating Objects from cluster [%s] to cluster [%s]:\n", c.Obj.Spec.DisplayName, tc.Obj.Spec.DisplayName)
for _, p := range c.ToMigrate.Projects {
if !p.Migrated {
fmt.Printf("- migrating Project [%s]... ", p.Name)
fmt.Fprintf(w, "- migrating Project [%s]... ", p.Name)
p.Mutate(tc)
if err := client.Projects.Create(ctx, tc.Obj.Name, p.Obj, nil, v1.CreateOptions{}); err != nil {
return err
}
fmt.Printf("Done.\n")
fmt.Fprintf(w, "Done.\n")
}

for _, prtb := range p.PRTBs {
if !prtb.Migrated {
fmt.Printf(" - migrating PRTB [%s]... ", prtb.Name)
fmt.Fprintf(w, " - migrating PRTB [%s]... ", prtb.Name)
// if project is already migrated then we find out the new project name in the mgirated cluster

prtb.Mutate(tc.Obj.Name, prtb.ProjectName)
if err := client.ProjectRoleTemplateBindings.Create(ctx, prtb.ProjectName, prtb.Obj, nil, v1.CreateOptions{}); err != nil {
return err
}
fmt.Printf("Done.\n")
fmt.Fprintf(w, "Done.\n")
}
}
for _, ns := range p.Namespaces {
if !ns.Migrated {
fmt.Printf(" - migrating Namespace [%s]... ", ns.Name)
fmt.Fprintf(w, " - migrating Namespace [%s]... ", ns.Name)
ns.Mutate(tc.Obj.Name, ns.ProjectName)
if _, err := tc.Client.Namespace.Create(ns.Obj); err != nil {
return err
}
fmt.Printf("Done.\n")
fmt.Fprintf(w, "Done.\n")
}
}
}
for _, crtb := range c.ToMigrate.CRTBs {
if !crtb.Migrated {
fmt.Printf("- migrating CRTB [%s]... ", crtb.Name)
fmt.Fprintf(w, "- migrating CRTB [%s]... ", crtb.Name)
crtb.Mutate(tc)
if err := client.ClusterRoleTemplateBindings.Create(ctx, tc.Obj.Name, crtb.Obj, nil, v1.CreateOptions{}); err != nil {
return err
}
fmt.Printf("Done.\n")
fmt.Fprintf(w, "Done.\n")
}
}
// catalog repos
for _, repo := range c.ToMigrate.ClusterRepos {
if !repo.Migrated {
fmt.Printf("- migrating catalog repo [%s]... ", repo.Name)
fmt.Fprintf(w, "- migrating catalog repo [%s]... ", repo.Name)
repo.Mutate()
if err := tc.Client.ClusterRepos.Create(ctx, tc.Obj.Name, repo.Obj, nil, v1.CreateOptions{}); err != nil {
return err
}
fmt.Printf("Done.\n")
fmt.Fprintf(w, "Done.\n")
}
}

Expand Down
61 changes: 54 additions & 7 deletions pkg/cluster/tui/cluster.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package tui

import (
"bytes"
"context"
"galal-hussein/cattle-drive/pkg/cluster/tui/constants"
"strings"
"time"

"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/list"
"github.com/charmbracelet/bubbles/progress"
tea "github.com/charmbracelet/bubbletea"
)

Expand All @@ -17,9 +22,11 @@ const (
)

type Model struct {
mode mode
list list.Model
quitting bool
mode mode
migratingAll bool
list list.Model
progress progress.Model
quitting bool
}

type item struct {
Expand All @@ -43,19 +50,22 @@ func (m Model) Init() tea.Cmd {
return nil
}

func InitCluster() (tea.Model, tea.Cmd) {
func InitCluster(msg tea.Msg) (tea.Model, tea.Cmd) {
prog := progress.New(progress.WithSolidFill("#04B575"))
items := newClusterList()
delegate := newItemDelegate(delegateKeys)
clusterList := list.New(items, delegate, 8, 8)
clusterList.Styles.Title = constants.TitleStyle

m := Model{mode: nav, list: clusterList}
m := Model{mode: nav, list: clusterList, progress: prog}
if constants.WindowSize.Height != 0 {
top, right, bottom, left := constants.DocStyle.GetMargin()
m.list.SetSize(constants.WindowSize.Width-left-right, constants.WindowSize.Height-top-bottom-1)
}
m.list.Title = "Cluster " + constants.SC.Obj.Spec.DisplayName + " migration"

if msg != nil {
return m, func() tea.Msg { return msg }
}
return m, func() tea.Msg { return errMsg{nil} }
}

Expand All @@ -73,6 +83,25 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
var cmds []tea.Cmd
switch msg := msg.(type) {
case tickMsg:
m.migratingAll = true
for {
select {
case <-time.After(time.Millisecond * 500):
if m.progress.Percent() == 1.0 {
cmd := m.progress.SetPercent(0)
return m, tea.Batch(tickCmd(), cmd)
}
cmd := m.progress.IncrPercent(0.25)
return m, tea.Batch(tickCmd(), cmd)
case <-constants.Migratedch:
return InitCluster(nil)
}
}
case progress.FrameMsg:
progressModel, cmd := m.progress.Update(msg)
m.progress = progressModel.(progress.Model)
return m, cmd
case tea.WindowSizeMsg:
constants.WindowSize = msg
top, right, bottom, left := constants.DocStyle.GetMargin()
Expand All @@ -85,7 +114,10 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case key.Matches(msg, delegateKeys.Enter):
entry := InitObjects(m.list.SelectedItem().(item))
return entry.Update(constants.WindowSize)

case key.Matches(msg, delegateKeys.MigrateAll):
m.mode = migrate
go m.migrateCluster(context.Background())
return InitCluster(tickMsg{})
default:
m.list, cmd = m.list.Update(msg)
}
Expand All @@ -100,5 +132,20 @@ func (m Model) View() string {
if m.quitting {
return ""
}
if m.migratingAll {
pad := strings.Repeat(" ", 2)
return "\n\n Migrating all objects.. please wait" + pad + m.progress.View() + "\n\n" + pad
}
return constants.DocStyle.Render(m.list.View() + "\n")
}

func (m *Model) migrateCluster(ctx context.Context) {
var buf bytes.Buffer
if err := constants.SC.Migrate(ctx, constants.Lclient, constants.TC, &buf); err != nil {
m.Update(tea.Quit())
}
if err := updateClusters(ctx); err != nil {
m.Update(tea.Quit())
}
constants.Migratedch <- true
}
1 change: 1 addition & 0 deletions pkg/cluster/tui/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var (
Lclient *client.Clients
// WindowSize store the size of the terminal window
WindowSize tea.WindowSizeMsg
Migratedch = make(chan bool)
)

/* STYLING */
Expand Down
17 changes: 12 additions & 5 deletions pkg/cluster/tui/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func newItemDelegate(keys *delegateKeyMap) list.DefaultDelegate {
return nil
}

help := []key.Binding{keys.Enter, keys.Migrate, keys.Back}
help := []key.Binding{keys.Enter, keys.Migrate, keys.MigrateAll, keys.Back}

d.ShortHelpFunc = func() []key.Binding {
return help
Expand All @@ -45,16 +45,18 @@ func newItemDelegate(keys *delegateKeyMap) list.DefaultDelegate {
}

type delegateKeyMap struct {
Migrate key.Binding
Back key.Binding
Enter key.Binding
Quit key.Binding
MigrateAll key.Binding
Migrate key.Binding
Back key.Binding
Enter key.Binding
Quit key.Binding
}

// Additional short help entries. This satisfies the help.KeyMap interface and
// is entirely optional.
func (d delegateKeyMap) ShortHelp() []key.Binding {
return []key.Binding{
d.MigrateAll,
d.Migrate,
d.Back,
d.Enter,
Expand All @@ -67,6 +69,7 @@ func (d delegateKeyMap) ShortHelp() []key.Binding {
func (d delegateKeyMap) FullHelp() [][]key.Binding {
return [][]key.Binding{
{
d.MigrateAll,
d.Migrate,
d.Back,
d.Enter,
Expand All @@ -85,6 +88,10 @@ func newDelegateKeyMap() *delegateKeyMap {
key.WithKeys("m"),
key.WithHelp("m", "migrate"),
),
MigrateAll: key.NewBinding(
key.WithKeys("a"),
key.WithHelp("a", "migrate all"),
),
Back: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "main menu"),
Expand Down
23 changes: 14 additions & 9 deletions pkg/cluster/tui/objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type Objects struct {
mode mode
list list.Model
quitting bool
percent float64
progress progress.Model
activeObject string
}
Expand Down Expand Up @@ -91,7 +90,9 @@ func InitObjects(i item) *Objects {
items = append(items, i)
}
}
delegate := newItemDelegate(delegateKeys)
delegateObjKeys := *delegateKeys
delegateObjKeys.MigrateAll = key.NewBinding()
delegate := newItemDelegate(&delegateObjKeys)
objList := list.New(items, delegate, 8, 8)
objList.Styles.Title = constants.TitleStyle
m.list = objList
Expand All @@ -113,19 +114,23 @@ func (m Objects) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
top, right, bottom, left := constants.DocStyle.GetMargin()
m.list.SetSize(msg.Width-left-right, msg.Height-top-bottom-1)
case tickMsg:
m.percent += 0.1
if m.percent > 1.0 || m.mode == migrated {
m.percent = 1.0
return InitCluster()
m.mode = migrate
cmd := m.progress.IncrPercent(0.25)
if m.progress.Percent() == 1.0 || m.mode == migrated {
return InitCluster(nil)
}
return m, tickCmd()
return m, tea.Batch(tickCmd(), cmd)
case progress.FrameMsg:
progressModel, cmd := m.progress.Update(msg)
m.progress = progressModel.(progress.Model)
return m, cmd
case tea.KeyMsg:
switch {
case key.Matches(msg, delegateKeys.Quit):
m.quitting = true
return m, tea.Quit
case key.Matches(msg, delegateKeys.Back):
return InitCluster()
return InitCluster(nil)
case key.Matches(msg, delegateKeys.Enter):
if m.list.SelectedItem() == nil {
return m, tea.Batch(cmds...)
Expand Down Expand Up @@ -162,7 +167,7 @@ func (m Objects) View() string {
}
if m.mode == migrate {
pad := strings.Repeat(" ", 2)
return "\n\n Waiting for object [" + m.activeObject + "] to be migrated\n\n" + pad + m.progress.ViewAs(m.percent) + "\n\n" + pad
return "\n\n Waiting for object [" + m.activeObject + "] to be migrated\n\n" + pad + m.progress.View() + "\n\n" + pad
}
return constants.DocStyle.Render(m.list.View() + "\n")
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cluster/tui/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func StartTea(sc, tc *cluster.Cluster, client *client.Clients) error {
constants.TC = tc
constants.Lclient = client

m, _ := InitCluster()
m, _ := InitCluster(nil)
constants.P = tea.NewProgram(m, tea.WithAltScreen())
if _, err := constants.P.Run(); err != nil {
return err
Expand Down

0 comments on commit 4811166

Please sign in to comment.