1// Copyright 2016-2017 VMware, Inc. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Package vmomi is in a separate package to avoid the transitive inclusion of govmomi 16// as a fundamental dependency of the main extraconfig 17package vmomi 18 19import ( 20 "fmt" 21 22 "github.com/vmware/govmomi/vim25/types" 23 "github.com/vmware/vic/pkg/vsphere/extraconfig" 24) 25 26// OptionValueMap returns a map from array of OptionValues 27func OptionValueMap(src []types.BaseOptionValue) map[string]string { 28 // create the key/value store from the extraconfig slice for lookups 29 kv := make(map[string]string) 30 for i := range src { 31 k := src[i].GetOptionValue().Key 32 v := src[i].GetOptionValue().Value.(string) 33 kv[k] = UnescapeNil(v) 34 } 35 return kv 36} 37 38// OptionValueSource is a convenience method to generate a MapSource source from 39// and array of OptionValue's 40func OptionValueSource(src []types.BaseOptionValue) extraconfig.DataSource { 41 kv := OptionValueMap(src) 42 return extraconfig.MapSource(kv) 43} 44 45// OptionValueFromMap is a convenience method to convert a map into a BaseOptionValue array 46// escapeNil - if true a nil string is replaced with "<nil>". Allows us to distinguish between 47// deletion and nil as a value 48func OptionValueFromMap(data map[string]string, escape bool) []types.BaseOptionValue { 49 if len(data) == 0 { 50 return nil 51 } 52 53 array := make([]types.BaseOptionValue, len(data)) 54 55 i := 0 56 for k, v := range data { 57 if escape { 58 v = EscapeNil(v) 59 } 60 array[i] = &types.OptionValue{Key: k, Value: v} 61 i++ 62 } 63 64 return array 65} 66 67// OptionValueArrayToString translates the options array in to a Go formatted structure dump 68func OptionValueArrayToString(options []types.BaseOptionValue) string { 69 // create the key/value store from the extraconfig slice for lookups 70 kv := make(map[string]string) 71 for i := range options { 72 k := options[i].GetOptionValue().Key 73 v := options[i].GetOptionValue().Value.(string) 74 kv[k] = v 75 } 76 77 return fmt.Sprintf("%#v", kv) 78} 79 80// OptionValueUpdatesFromMap generates an optionValue array for those entries in the map that do not 81// already exist, are changed from the reference array, or a removed 82// A removed entry will have a nil string for the value 83// NOTE: DOES NOT CURRENTLY SUPPORT DELETION OF KEYS - KEYS MISSING FROM NEW MAP ARE IGNORED 84func OptionValueUpdatesFromMap(existing []types.BaseOptionValue, new map[string]string) []types.BaseOptionValue { 85 e := len(existing) 86 if e == 0 { 87 return OptionValueFromMap(new, true) 88 } 89 90 n := len(new) 91 updates := make(map[string]string, n+e) 92 unchanged := make(map[string]struct{}, n+e) 93 94 // first the existing keys 95 for i := range existing { 96 v := existing[i].GetOptionValue() 97 if nV, ok := new[v.Key]; ok && nV == v.Value.(string) { 98 unchanged[v.Key] = struct{}{} 99 // no change 100 continue 101 } else if ok { 102 // changed 103 updates[v.Key] = EscapeNil(nV) 104 } else { 105 // deletion 106 // NOTE: ignored as this also deletes non VIC entries currently 107 // there's no prefix for the non-guestinfo keys so cannot easily filter 108 // updates[v.Key] = "" 109 } 110 } 111 112 // now the new keys 113 for k, v := range new { 114 if _, ok := unchanged[k]; ok { 115 continue 116 } 117 118 if _, ok := updates[k]; !ok { 119 updates[k] = EscapeNil(v) 120 } 121 } 122 123 return OptionValueFromMap(updates, false) 124} 125 126func EscapeNil(input string) string { 127 if input == "" { 128 return "<nil>" 129 } 130 131 return input 132} 133 134func UnescapeNil(input string) string { 135 if input == "<nil>" { 136 return "" 137 } 138 139 return input 140} 141