github.com/vmware/govmomi@v0.51.0/cli/vm/snapshot/tree.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package snapshot 6 7 import ( 8 "context" 9 "encoding/json" 10 "flag" 11 "fmt" 12 "path" 13 "strings" 14 "time" 15 16 "github.com/vmware/govmomi/cli" 17 "github.com/vmware/govmomi/cli/flags" 18 "github.com/vmware/govmomi/object" 19 "github.com/vmware/govmomi/units" 20 "github.com/vmware/govmomi/vim25/mo" 21 "github.com/vmware/govmomi/vim25/types" 22 ) 23 24 type tree struct { 25 *flags.VirtualMachineFlag 26 27 current bool 28 currentName bool 29 date bool 30 description bool 31 fullPath bool 32 id bool 33 size bool 34 35 info *types.VirtualMachineSnapshotInfo 36 layout *types.VirtualMachineFileLayoutEx 37 } 38 39 func init() { 40 cli.Register("snapshot.tree", &tree{}) 41 } 42 43 func (cmd *tree) Register(ctx context.Context, f *flag.FlagSet) { 44 cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx) 45 cmd.VirtualMachineFlag.Register(ctx, f) 46 47 f.BoolVar(&cmd.current, "c", true, "Print the current snapshot") 48 f.BoolVar(&cmd.currentName, "C", false, 49 "Print the current snapshot name only") 50 f.BoolVar(&cmd.date, "D", false, "Print the snapshot creation date") 51 f.BoolVar(&cmd.description, "d", false, 52 "Print the snapshot description") 53 f.BoolVar(&cmd.fullPath, "f", false, 54 "Print the full path prefix for snapshot") 55 f.BoolVar(&cmd.id, "i", false, "Print the snapshot id") 56 f.BoolVar(&cmd.size, "s", false, "Print the snapshot size") 57 } 58 59 func (cmd *tree) Description() string { 60 return `List VM snapshots in a tree-like format. 61 62 The command will exit 0 with no output if VM does not have any snapshots. 63 64 Examples: 65 govc snapshot.tree -vm my-vm 66 govc snapshot.tree -vm my-vm -D -i -d` 67 } 68 69 func (cmd *tree) Process(ctx context.Context) error { 70 if err := cmd.VirtualMachineFlag.Process(ctx); err != nil { 71 return err 72 } 73 return nil 74 } 75 76 type SnapshotRecord struct { 77 CreateTime *time.Time `json:"createTime,omitempty"` 78 Id *string `json:"id,omitempty"` 79 Size *int `json:"size,omitempty"` 80 Name string `json:"name"` 81 Description *string `json:"description,omitempty"` 82 IsCurrent bool `json:"current"` 83 ChildSnapshotList []SnapshotRecord `json:"childSnapshotList"` 84 } 85 86 func (cmd *tree) IsCurrent(vm mo.VirtualMachine, moref types.ManagedObjectReference) bool { 87 return vm.Snapshot.CurrentSnapshot.Value == moref.Value 88 } 89 90 func (cmd *tree) CreateTime(snapshot types.VirtualMachineSnapshotTree) *time.Time { 91 if cmd.date { 92 return &snapshot.CreateTime 93 } 94 return nil 95 96 } 97 98 func (cmd *tree) SnapshotId(snapshot types.VirtualMachineSnapshotTree) *string { 99 if cmd.id { 100 return &snapshot.Snapshot.Value 101 } 102 return nil 103 } 104 105 func (cmd *tree) SnapshotDescription(snapshot types.VirtualMachineSnapshotTree) *string { 106 if cmd.description { 107 return &snapshot.Description 108 } 109 return nil 110 } 111 112 func (cmd *tree) SnapshotSize(vm mo.VirtualMachine, snapshot types.ManagedObjectReference, parent *types.ManagedObjectReference) *int { 113 if cmd.size { 114 size := object.SnapshotSize(snapshot, parent, vm.LayoutEx, cmd.IsCurrent(vm, snapshot)) 115 return &size 116 } 117 return nil 118 } 119 120 func (cmd *tree) makeSnapshotRecord(vm mo.VirtualMachine, node types.VirtualMachineSnapshotTree, parent *types.ManagedObjectReference) SnapshotRecord { 121 122 var SnapshotRecords []SnapshotRecord 123 for _, snapshot := range node.ChildSnapshotList { 124 SnapshotRecords = append(SnapshotRecords, cmd.makeSnapshotRecord(vm, snapshot, &node.Snapshot)) 125 } 126 return SnapshotRecord{Name: node.Name, 127 Id: cmd.SnapshotId(node), 128 CreateTime: cmd.CreateTime(node), 129 Description: cmd.SnapshotDescription(node), 130 ChildSnapshotList: SnapshotRecords, 131 Size: cmd.SnapshotSize(vm, node.Snapshot, parent), 132 IsCurrent: cmd.IsCurrent(vm, node.Snapshot)} 133 134 } 135 136 func (cmd *tree) writeJson(vm mo.VirtualMachine) { 137 var SnapshotRecords []SnapshotRecord 138 for _, rootSnapshot := range vm.Snapshot.RootSnapshotList { 139 SnapshotRecords = append(SnapshotRecords, cmd.makeSnapshotRecord(vm, rootSnapshot, nil)) 140 } 141 b, _ := json.MarshalIndent(SnapshotRecords, "", " ") 142 fmt.Println(string(b)) 143 144 } 145 func (cmd *tree) write(level int, parent string, pref *types.ManagedObjectReference, st []types.VirtualMachineSnapshotTree) { 146 for _, s := range st { 147 s := s // avoid implicit memory aliasing 148 149 sname := s.Name 150 if cmd.fullPath && parent != "" { 151 sname = path.Join(parent, sname) 152 } 153 154 var names []string 155 156 if !cmd.currentName { 157 names = append(names, sname) 158 } 159 160 isCurrent := false 161 162 if s.Snapshot == *cmd.info.CurrentSnapshot { 163 isCurrent = true 164 if cmd.current { 165 names = append(names, ".") 166 } else if cmd.currentName { 167 fmt.Println(sname) 168 return 169 } 170 } 171 172 for _, name := range names { 173 var attr []string 174 var meta string 175 176 if cmd.size { 177 size := object.SnapshotSize(s.Snapshot, pref, cmd.layout, isCurrent) 178 179 attr = append(attr, units.ByteSize(size).String()) 180 } 181 182 if cmd.id { 183 attr = append(attr, s.Snapshot.Value) 184 } 185 186 if cmd.date { 187 attr = append(attr, s.CreateTime.Format("2006-01-02T15:04:05Z07:00")) 188 } 189 190 if len(attr) > 0 { 191 meta = fmt.Sprintf("[%s] ", strings.Join(attr, " ")) 192 } 193 194 if cmd.description { 195 fmt.Printf("%s%s%s - %4s\n", 196 strings.Repeat(" ", level), meta, name, 197 s.Description) 198 } else { 199 fmt.Printf("%s%s%s\n", 200 strings.Repeat(" ", level), meta, name) 201 } 202 } 203 204 cmd.write(level+2, sname, &s.Snapshot, s.ChildSnapshotList) 205 } 206 } 207 208 func (cmd *tree) Run(ctx context.Context, f *flag.FlagSet) error { 209 if f.NArg() != 0 { 210 return flag.ErrHelp 211 } 212 213 vm, err := cmd.VirtualMachine() 214 if err != nil { 215 return err 216 } 217 218 if vm == nil { 219 return flag.ErrHelp 220 } 221 222 var o mo.VirtualMachine 223 224 err = vm.Properties(ctx, vm.Reference(), []string{"snapshot", "layoutEx"}, &o) 225 if err != nil { 226 return err 227 } 228 229 if o.Snapshot == nil { 230 return nil 231 } 232 233 if o.Snapshot.CurrentSnapshot == nil || cmd.currentName { 234 cmd.current = false 235 } 236 237 cmd.info = o.Snapshot 238 cmd.layout = o.LayoutEx 239 if cmd.JSON { 240 cmd.writeJson(o) 241 } else { 242 cmd.write(0, "", nil, o.Snapshot.RootSnapshotList) 243 } 244 245 return nil 246 }