Skip to content

Commit

Permalink
Skip already imported resources
Browse files Browse the repository at this point in the history
Add a `Imported` flag for each import item, if it is imported then set
that flag. In case users hit some import error, the users can adjust the
resource types for each import item. In case users adjust the resource
type for an already imported resource, the tool will remove that
resource from the state and mark it as not imported, which will cause
this resource to be imported in the next apply.
  • Loading branch information
magodo committed Jan 27, 2022
1 parent 82c9569 commit 3d4cdcd
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 39 deletions.
10 changes: 6 additions & 4 deletions internal/meta/importlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ type ImportItem struct {
// Whether this azure resource failed to import into terraform (this might due to the TFResourceType doesn't match the resource)
ImportError error

// Whether this azure resource has been successfully imported
Imported bool

// Whether this azure resource failed to validate into terraform (tbh, this should reside in UI layer only)
ValidateError error

Expand Down Expand Up @@ -54,11 +57,10 @@ func (l ImportList) ImportErrored() ImportList {

func (l ImportList) Imported() ImportList {
var out ImportList
for _, item := range l.NonSkipped() {
if item.ImportError != nil {
continue
for _, item := range l {
if item.Imported {
out = append(out, item)
}
out = append(out, item)
}
return out
}
2 changes: 1 addition & 1 deletion internal/meta/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type Meta interface {
ResourceGroupName() string
Workspace() string
ListResource() ImportList
CleanTFState()
CleanTFState(addr string)
Import(item ImportItem) error
GenerateCfg(l ImportList) error
}
Expand Down
2 changes: 1 addition & 1 deletion internal/meta/meta_dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (m MetaDummy) ListResource() ImportList {
}
}

func (m MetaDummy) CleanTFState() {
func (m MetaDummy) CleanTFState(_ string) {
return
}

Expand Down
11 changes: 6 additions & 5 deletions internal/meta/meta_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"

Expand Down Expand Up @@ -139,16 +138,18 @@ func (meta MetaImpl) ListResource() ImportList {
ids = append(ids, armtemplate.ResourceGroupId.ID(meta.subscriptionId, meta.resourceGroup))

l := make(ImportList, 0, len(ids))
for _, id := range ids {
for i, id := range ids {
l = append(l, ImportItem{
ResourceID: id,
ResourceID: id,
TFResourceName: fmt.Sprintf("res-%d", i),
})
}
return l
}

func (meta *MetaImpl) CleanTFState() {
os.Remove(path.Join(meta.Workspace(), "terraform.tfstate"))
func (meta *MetaImpl) CleanTFState(addr string) {
ctx := context.TODO()
meta.tf.StateRm(ctx, addr)
}

func (meta MetaImpl) Import(item ImportItem) error {
Expand Down
17 changes: 14 additions & 3 deletions internal/ui/aztfyclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ type ImportDoneMsg struct {
List meta.ImportList
}

type CleanTFStateMsg struct {
Addr string
}

type GenerateCfgDoneMsg struct{}

type QuitMsg struct{}
Expand Down Expand Up @@ -75,15 +79,16 @@ func ShowImportError(item meta.ImportItem, idx int, l meta.ImportList) tea.Cmd {

func StartImport(c meta.Meta, l meta.ImportList) tea.Cmd {
return func() tea.Msg {
c.CleanTFState()
return StartImportMsg{List: l}
}
}

func ImportOneItem(c meta.Meta, item meta.ImportItem) tea.Cmd {
return func() tea.Msg {
if !item.Skip() {
item.ImportError = c.Import(item)
if !item.Skip() && !item.Imported {
err := c.Import(item)
item.Imported = err == nil
item.ImportError = err
} else {
// This explicit minor delay is for the sake of a visual effect of the progress bar.
time.Sleep(100 * time.Millisecond)
Expand All @@ -107,6 +112,12 @@ func GenerateCfg(c meta.Meta, l meta.ImportList) tea.Cmd {
}
}

func CleanTFState(addr string) tea.Cmd {
return func() tea.Msg {
return CleanTFStateMsg{addr}
}
}

func Quit() tea.Cmd {
return func() tea.Msg {
return QuitMsg{}
Expand Down
1 change: 1 addition & 0 deletions internal/ui/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

const ErrorEmoji = "❗️"
const WarningEmoji = "❓"
const OKEmoji = "✅"

// Colors for dark and light backgrounds.
var (
Expand Down
2 changes: 1 addition & 1 deletion internal/ui/importlist/importlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func NewModel(c meta.Meta, l meta.ImportList, idx int) Model {
ti := textinput.NewModel()
ti.SetCursorMode(textinput.CursorStatic)
if !item.Skip() {
ti.SetValue(fmt.Sprintf("%s.%s", item.TFResourceType, item.TFResourceName))
ti.SetValue(item.TFResourceType)
}
ti.CandidateWords = candidates
items = append(items, Item{
Expand Down
10 changes: 10 additions & 0 deletions internal/ui/importlist/importlist_delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"strings"

"github.com/Azure/aztfy/internal/ui/aztfyclient"
"github.com/Azure/aztfy/internal/ui/common"
"github.com/Azure/aztfy/schema"

Expand Down Expand Up @@ -37,6 +38,15 @@ func NewImportItemDelegate() list.ItemDelegate {
// Clear the validation error that were set.
selItem.v.ValidateError = nil

// Clear the imported flag that were set, which means this resource will be imported again.
// This allows the user to change its mind for importing this resource as another resource type.
// (e.g. vm resource -> either azurerm_virtual_machine or azurerm_linux_virtual_machine)
if selItem.v.Imported {
cmd := aztfyclient.CleanTFState(selItem.v.TFAddr())
cmds = append(cmds, cmd)
selItem.v.Imported = false
}

// "Enter" focus current selected item
setListKeyMapEnabled(m, false)
cmd := selItem.textinput.Focus()
Expand Down
2 changes: 2 additions & 0 deletions internal/ui/importlist/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func (i Item) Title() string {
return common.WarningEmoji + i.v.ResourceID
case i.v.ImportError != nil:
return common.ErrorEmoji + i.v.ResourceID
case i.v.Imported:
return common.OKEmoji + i.v.ResourceID
default:
return i.v.ResourceID
}
Expand Down
10 changes: 6 additions & 4 deletions internal/ui/progress/progress.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,12 @@ func (m Model) View() string {
switch {
case res.item.Skip():
s += fmt.Sprintf("%s %s skipped\n", res.emoji, res.item.ResourceID)
case res.item.ImportError == nil:
s += fmt.Sprintf("%s %s import successfully\n", res.emoji, res.item.ResourceID)
case res.item.ImportError != nil:
s += fmt.Sprintf("%s %s import failed\n", res.emoji, res.item.ResourceID)
default:
if res.item.ImportError == nil {
s += fmt.Sprintf("%s %s import successfully\n", res.emoji, res.item.ResourceID)
} else {
s += fmt.Sprintf("%s %s import failed\n", res.emoji, res.item.ResourceID)
}
}
}
}
Expand Down
23 changes: 3 additions & 20 deletions internal/ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,26 +144,6 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.importerrormsg = msg
return m, nil
case aztfyclient.StartImportMsg:
// Update the import list to give each import item a resource name, unique among each resource type.
tm := map[string]map[string]bool{}
for i, item := range msg.List {
if item.Skip() {
continue
}
nm, ok := tm[item.TFResourceType]
if !ok {
nm = map[string]bool{}
tm[item.TFResourceType] = nm
}
for idx := 0; ; idx++ {
name := fmt.Sprintf("this-%d", idx)
if _, ok := nm[name]; !ok {
nm[name] = true
msg.List[i].TFResourceName = name
break
}
}
}
m.status = statusImporting
m.progress = progress.NewModel(m.meta, msg.List)
return m, tea.Batch(
Expand All @@ -182,6 +162,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
m.status = statusGeneratingCfg
return m, aztfyclient.GenerateCfg(m.meta, msg.List)
case aztfyclient.CleanTFStateMsg:
m.meta.CleanTFState(msg.Addr)
return m, nil
case aztfyclient.GenerateCfgDoneMsg:
m.status = statusSummary
return m, nil
Expand Down

0 comments on commit 3d4cdcd

Please sign in to comment.