github.com/vmware/govmomi@v0.37.1/govc/importx/options.go (about) 1 /* 2 Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package importx 18 19 import ( 20 "context" 21 "encoding/json" 22 "flag" 23 "fmt" 24 "os" 25 26 "github.com/vmware/govmomi/govc/flags" 27 "github.com/vmware/govmomi/object" 28 "github.com/vmware/govmomi/ovf" 29 "github.com/vmware/govmomi/vim25/types" 30 ) 31 32 type KeyValue struct { 33 Key string 34 Value string 35 } 36 37 // case insensitive for Key + Value 38 func (kv *KeyValue) UnmarshalJSON(b []byte) error { 39 e := struct { 40 types.KeyValue 41 Key *string 42 Value *string 43 }{ 44 types.KeyValue{}, &kv.Key, &kv.Value, 45 } 46 47 err := json.Unmarshal(b, &e) 48 if err != nil { 49 return err 50 } 51 52 if kv.Key == "" { 53 kv.Key = e.KeyValue.Key // "key" 54 } 55 56 if kv.Value == "" { 57 kv.Value = e.KeyValue.Value // "value" 58 } 59 60 return nil 61 } 62 63 type Property struct { 64 KeyValue 65 Spec *ovf.Property `json:",omitempty"` 66 } 67 68 type Network struct { 69 Name string 70 Network string 71 } 72 73 type Options struct { 74 AllDeploymentOptions []string `json:",omitempty"` 75 Deployment string `json:",omitempty"` 76 77 AllDiskProvisioningOptions []string `json:",omitempty"` 78 DiskProvisioning string 79 80 AllIPAllocationPolicyOptions []string `json:",omitempty"` 81 IPAllocationPolicy string 82 83 AllIPProtocolOptions []string `json:",omitempty"` 84 IPProtocol string 85 86 PropertyMapping []Property `json:",omitempty"` 87 88 NetworkMapping []Network `json:",omitempty"` 89 90 Annotation string `json:",omitempty"` 91 92 MarkAsTemplate bool 93 PowerOn bool 94 InjectOvfEnv bool 95 WaitForIP bool 96 Name *string 97 } 98 99 type OptionsFlag struct { 100 Options Options 101 102 path string 103 } 104 105 func newOptionsFlag(ctx context.Context) (*OptionsFlag, context.Context) { 106 return &OptionsFlag{}, ctx 107 } 108 109 func (flag *OptionsFlag) Register(ctx context.Context, f *flag.FlagSet) { 110 f.StringVar(&flag.path, "options", "", "Options spec file path for VM deployment") 111 } 112 113 func (flag *OptionsFlag) Process(ctx context.Context) error { 114 if len(flag.path) == 0 { 115 return nil 116 } 117 118 var err error 119 in := os.Stdin 120 121 if flag.path != "-" { 122 in, err = os.Open(flag.path) 123 if err != nil { 124 return err 125 } 126 defer in.Close() 127 } 128 129 return json.NewDecoder(in).Decode(&flag.Options) 130 } 131 132 func (flag *OptionsFlag) powerOn(vm *object.VirtualMachine, out *flags.OutputFlag) error { 133 if !flag.Options.PowerOn || flag.Options.MarkAsTemplate { 134 return nil 135 } 136 137 out.Log("Powering on VM...\n") 138 139 task, err := vm.PowerOn(context.Background()) 140 if err != nil { 141 return err 142 } 143 144 return task.Wait(context.Background()) 145 } 146 147 func (flag *OptionsFlag) markAsTemplate(vm *object.VirtualMachine, out *flags.OutputFlag) error { 148 if !flag.Options.MarkAsTemplate { 149 return nil 150 } 151 152 out.Log("Marking VM as template...\n") 153 154 return vm.MarkAsTemplate(context.Background()) 155 } 156 157 func (flag *OptionsFlag) injectOvfEnv(vm *object.VirtualMachine, out *flags.OutputFlag) error { 158 if !flag.Options.InjectOvfEnv { 159 return nil 160 } 161 162 out.Log("Injecting OVF environment...\n") 163 164 var opts []types.BaseOptionValue 165 166 a := vm.Client().ServiceContent.About 167 168 // build up Environment in order to marshal to xml 169 var props []ovf.EnvProperty 170 for _, p := range flag.Options.PropertyMapping { 171 props = append(props, ovf.EnvProperty{ 172 Key: p.Key, 173 Value: p.Value, 174 }) 175 } 176 177 env := ovf.Env{ 178 EsxID: vm.Reference().Value, 179 Platform: &ovf.PlatformSection{ 180 Kind: a.Name, 181 Version: a.Version, 182 Vendor: a.Vendor, 183 Locale: "US", 184 }, 185 Property: &ovf.PropertySection{ 186 Properties: props, 187 }, 188 } 189 190 opts = append(opts, &types.OptionValue{ 191 Key: "guestinfo.ovfEnv", 192 Value: env.MarshalManual(), 193 }) 194 195 task, err := vm.Reconfigure(context.Background(), types.VirtualMachineConfigSpec{ 196 ExtraConfig: opts, 197 }) 198 199 if err != nil { 200 return err 201 } 202 203 return task.Wait(context.Background()) 204 } 205 206 func (flag *OptionsFlag) waitForIP(vm *object.VirtualMachine, out *flags.OutputFlag) error { 207 if !flag.Options.PowerOn || !flag.Options.WaitForIP || flag.Options.MarkAsTemplate { 208 return nil 209 } 210 211 out.Log("Waiting for IP address...\n") 212 ip, err := vm.WaitForIP(context.Background()) 213 if err != nil { 214 return err 215 } 216 217 out.Log(fmt.Sprintf("Received IP address: %s\n", ip)) 218 return nil 219 } 220 221 func (flag *OptionsFlag) Deploy(vm *object.VirtualMachine, out *flags.OutputFlag) error { 222 deploy := []func(*object.VirtualMachine, *flags.OutputFlag) error{ 223 flag.injectOvfEnv, 224 flag.markAsTemplate, 225 flag.powerOn, 226 flag.waitForIP, 227 } 228 229 for _, step := range deploy { 230 if err := step(vm, out); err != nil { 231 return err 232 } 233 } 234 235 return nil 236 }