1/*
2Copyright (c) 2016 VMware, Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package snapshot
18
19import (
20	"context"
21	"flag"
22	"fmt"
23	"path"
24	"strings"
25
26	"github.com/vmware/govmomi/govc/cli"
27	"github.com/vmware/govmomi/govc/flags"
28	"github.com/vmware/govmomi/vim25/mo"
29	"github.com/vmware/govmomi/vim25/types"
30)
31
32type tree struct {
33	*flags.VirtualMachineFlag
34
35	fullPath    bool
36	current     bool
37	currentName bool
38	date        bool
39	id          bool
40
41	info *types.VirtualMachineSnapshotInfo
42}
43
44func init() {
45	cli.Register("snapshot.tree", &tree{})
46}
47
48func (cmd *tree) Register(ctx context.Context, f *flag.FlagSet) {
49	cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
50	cmd.VirtualMachineFlag.Register(ctx, f)
51
52	f.BoolVar(&cmd.fullPath, "f", false, "Print the full path prefix for snapshot")
53	f.BoolVar(&cmd.currentName, "C", false, "Print the current snapshot name only")
54	f.BoolVar(&cmd.current, "c", true, "Print the current snapshot")
55	f.BoolVar(&cmd.date, "D", false, "Print the snapshot creation date")
56	f.BoolVar(&cmd.id, "i", false, "Print the snapshot id")
57}
58
59func (cmd *tree) Description() string {
60	return `List VM snapshots in a tree-like format.
61
62The command will exit 0 with no output if VM does not have any snapshots.
63
64Examples:
65  govc snapshot.tree -vm my-vm
66  govc snapshot.tree -vm my-vm -D -i`
67}
68
69func (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
76func (cmd *tree) write(level int, parent string, st []types.VirtualMachineSnapshotTree) {
77	for _, s := range st {
78		sname := s.Name
79
80		if cmd.fullPath && parent != "" {
81			sname = path.Join(parent, sname)
82		}
83
84		var names []string
85
86		if !cmd.currentName {
87			names = append(names, sname)
88		}
89
90		if s.Snapshot == *cmd.info.CurrentSnapshot {
91			if cmd.current {
92				names = append(names, ".")
93			} else if cmd.currentName {
94				fmt.Println(sname)
95				return
96			}
97		}
98
99		for _, name := range names {
100			var attr []string
101			var meta string
102
103			if cmd.id {
104				attr = append(attr, s.Snapshot.Value)
105			}
106
107			if cmd.date {
108				attr = append(attr, s.CreateTime.Format("Jan 2 15:04"))
109			}
110
111			if len(attr) > 0 {
112				meta = fmt.Sprintf("[%s]  ", strings.Join(attr, " "))
113			}
114
115			fmt.Printf("%s%s%s\n", strings.Repeat(" ", level), meta, name)
116		}
117
118		cmd.write(level+2, sname, s.ChildSnapshotList)
119	}
120}
121
122func (cmd *tree) Run(ctx context.Context, f *flag.FlagSet) error {
123	if f.NArg() != 0 {
124		return flag.ErrHelp
125	}
126
127	vm, err := cmd.VirtualMachine()
128	if err != nil {
129		return err
130	}
131
132	if vm == nil {
133		return flag.ErrHelp
134	}
135
136	var o mo.VirtualMachine
137
138	err = vm.Properties(ctx, vm.Reference(), []string{"snapshot"}, &o)
139	if err != nil {
140		return err
141	}
142
143	if o.Snapshot == nil {
144		return nil
145	}
146
147	if o.Snapshot.CurrentSnapshot == nil || cmd.currentName {
148		cmd.current = false
149	}
150
151	cmd.info = o.Snapshot
152
153	cmd.write(0, "", o.Snapshot.RootSnapshotList)
154
155	return nil
156}
157