func (h *UiHook) PreApply( n *terraform.InstanceInfo, s *terraform.InstanceState, d *terraform.InstanceDiff) (terraform.HookAction, error) { h.once.Do(h.init) id := n.HumanId() op := uiResourceModify if d.Destroy { op = uiResourceDestroy } else if s.ID == "" { op = uiResourceCreate } h.l.Lock() h.resources[id] = uiResourceState{ Op: op, Start: time.Now().Round(time.Second), } h.l.Unlock() var operation string switch op { case uiResourceModify: operation = "Modifying..." case uiResourceDestroy: operation = "Destroying..." case uiResourceCreate: operation = "Creating..." case uiResourceUnknown: return terraform.HookActionContinue, nil } attrBuf := new(bytes.Buffer) // Get all the attributes that are changing, and sort them. Also // determine the longest key so that we can align them all. keyLen := 0 dAttrs := d.CopyAttributes() keys := make([]string, 0, len(dAttrs)) for key, _ := range dAttrs { // Skip the ID since we do that specially if key == "id" { continue } keys = append(keys, key) if len(key) > keyLen { keyLen = len(key) } } sort.Strings(keys) // Go through and output each attribute for _, attrK := range keys { attrDiff, _ := d.GetAttribute(attrK) v := attrDiff.New u := attrDiff.Old if attrDiff.NewComputed { v = "<computed>" } if attrDiff.Sensitive { u = "<sensitive>" v = "<sensitive>" } attrBuf.WriteString(fmt.Sprintf( " %s:%s %#v => %#v\n", attrK, strings.Repeat(" ", keyLen-len(attrK)), u, v)) } attrString := strings.TrimSpace(attrBuf.String()) if attrString != "" { attrString = "\n " + attrString } h.ui.Output(h.Colorize.Color(fmt.Sprintf( "[reset][bold]%s: %s[reset_bold]%s", id, operation, attrString))) // Set a timer to show an operation is still happening time.AfterFunc(periodicUiTimer, func() { h.stillApplying(id) }) return terraform.HookActionContinue, nil }