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  }