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 vm
18
19import (
20	"context"
21	"flag"
22	"fmt"
23
24	"github.com/vmware/govmomi/govc/cli"
25	"github.com/vmware/govmomi/govc/flags"
26	"github.com/vmware/govmomi/object"
27	"github.com/vmware/govmomi/vim25/types"
28)
29
30type migrate struct {
31	*flags.ResourcePoolFlag
32	*flags.HostSystemFlag
33	*flags.DatastoreFlag
34	*flags.SearchFlag
35
36	priority types.VirtualMachineMovePriority
37	spec     types.VirtualMachineRelocateSpec
38}
39
40func init() {
41	cli.Register("vm.migrate", &migrate{})
42}
43
44func (cmd *migrate) Register(ctx context.Context, f *flag.FlagSet) {
45	cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
46	cmd.SearchFlag.Register(ctx, f)
47
48	cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
49	cmd.ResourcePoolFlag.Register(ctx, f)
50
51	cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
52	cmd.HostSystemFlag.Register(ctx, f)
53
54	cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
55	cmd.DatastoreFlag.Register(ctx, f)
56
57	f.StringVar((*string)(&cmd.priority), "priority", string(types.VirtualMachineMovePriorityDefaultPriority), "The task priority")
58}
59
60func (cmd *migrate) Process(ctx context.Context) error {
61	if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
62		return err
63	}
64	if err := cmd.HostSystemFlag.Process(ctx); err != nil {
65		return err
66	}
67	if err := cmd.DatastoreFlag.Process(ctx); err != nil {
68		return err
69	}
70
71	return nil
72}
73
74func (cmd *migrate) Usage() string {
75	return "VM..."
76}
77
78func (cmd *migrate) Description() string {
79	return `Migrates VM to a specific resource pool, host or datastore.
80
81Examples:
82  govc vm.migrate -host another-host vm-1 vm-2 vm-3
83  govc vm.migrate -pool another-pool vm-1 vm-2 vm-3
84  govc vm.migrate -ds another-ds vm-1 vm-2 vm-3`
85}
86
87func (cmd *migrate) relocate(ctx context.Context, vm *object.VirtualMachine) error {
88	task, err := vm.Relocate(ctx, cmd.spec, cmd.priority)
89	if err != nil {
90		return err
91	}
92
93	logger := cmd.DatastoreFlag.ProgressLogger(fmt.Sprintf("migrating %s... ", vm.Reference()))
94	_, err = task.WaitForResult(ctx, logger)
95	if err != nil {
96		return err
97	}
98
99	logger.Wait()
100
101	return nil
102}
103
104func (cmd *migrate) Run(ctx context.Context, f *flag.FlagSet) error {
105	vms, err := cmd.VirtualMachines(f.Args())
106	if err != nil {
107		return err
108	}
109
110	host, err := cmd.HostSystemFlag.HostSystemIfSpecified()
111	if err != nil {
112		return err
113	}
114
115	if host != nil {
116		ref := host.Reference()
117		cmd.spec.Host = &ref
118	}
119
120	pool, err := cmd.ResourcePoolFlag.ResourcePoolIfSpecified()
121	if err != nil {
122		return err
123	}
124
125	if pool == nil && host != nil {
126		pool, err = host.ResourcePool(ctx)
127		if err != nil {
128			return err
129		}
130	}
131
132	if pool != nil {
133		ref := pool.Reference()
134		cmd.spec.Pool = &ref
135	}
136
137	ds, err := cmd.DatastoreFlag.DatastoreIfSpecified()
138	if err != nil {
139		return err
140	}
141
142	if ds != nil {
143		ref := ds.Reference()
144		cmd.spec.Datastore = &ref
145	}
146
147	for _, vm := range vms {
148		err = cmd.relocate(ctx, vm)
149		if err != nil {
150			return err
151		}
152	}
153
154	return nil
155}
156