Clean NewVM func
This commit is contained in:
parent
122d5b1089
commit
cd5b6dc48d
6 changed files with 360 additions and 184 deletions
|
|
@ -11,10 +11,10 @@ import (
|
|||
type ArgAcceptedValue string
|
||||
|
||||
const (
|
||||
ArgAcceptedValueUint ArgAcceptedValue = "uint"
|
||||
ArgAcceptedValueString ArgAcceptedValue = "string"
|
||||
ArgAcceptedValueMap ArgAcceptedValue = "map"
|
||||
ArgAcceptedValueNone ArgAcceptedValue = "none"
|
||||
ArgAcceptedValueUint ArgAcceptedValue = "uint"
|
||||
ArgAcceptedValueString ArgAcceptedValue = "string"
|
||||
ArgAcceptedValueKeyValue ArgAcceptedValue = "kv"
|
||||
ArgAcceptedValueNone ArgAcceptedValue = "none"
|
||||
)
|
||||
|
||||
var safeArgs = map[string]ArgAcceptedValue{
|
||||
|
|
@ -22,12 +22,14 @@ var safeArgs = map[string]ArgAcceptedValue{
|
|||
"boot": ArgAcceptedValueString,
|
||||
"m": ArgAcceptedValueUint,
|
||||
"smp": ArgAcceptedValueUint,
|
||||
"device": ArgAcceptedValueMap,
|
||||
"netdev": ArgAcceptedValueMap,
|
||||
"device": ArgAcceptedValueKeyValue,
|
||||
"netdev": ArgAcceptedValueKeyValue,
|
||||
"serial": ArgAcceptedValueString,
|
||||
"cdrom": ArgAcceptedValueString,
|
||||
"machine": ArgAcceptedValueString,
|
||||
"cpu": ArgAcceptedValueString,
|
||||
"display": ArgAcceptedValueString,
|
||||
"drive": ArgAcceptedValueKeyValue,
|
||||
}
|
||||
|
||||
type Arg interface {
|
||||
|
|
@ -47,7 +49,7 @@ func EncodeArgs(args []Arg) ([]string, error) {
|
|||
|
||||
cmdArgs = append(cmdArgs, flag)
|
||||
if value != nil {
|
||||
cmdArgs = append(cmdArgs, shellescape.Quote(*value))
|
||||
cmdArgs = append(cmdArgs, *value)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,5 +80,7 @@ func EncodeArg(a Arg) (string, *string, error) {
|
|||
return "", nil, fmt.Errorf("empty string value while declaring non-empty value (type %v)", reflect.TypeOf(a))
|
||||
}
|
||||
|
||||
return "-" + argKey, &argValueStr, nil
|
||||
argVal := shellescape.Quote(argValueStr)
|
||||
|
||||
return "-" + argKey, &argVal, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,13 +7,18 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type MapArg struct {
|
||||
key string
|
||||
values map[string]string
|
||||
type KeyValueArgItem struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
func MustNewMapArg(key string, values map[string]string) *MapArg {
|
||||
a, err := NewMapArg(key, values)
|
||||
type KeyValueArg struct {
|
||||
key string
|
||||
items []KeyValueArgItem
|
||||
}
|
||||
|
||||
func MustNewKeyValueArg(key string, items []KeyValueArgItem) *KeyValueArg {
|
||||
a, err := NewKeyValueArg(key, items)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -21,10 +26,13 @@ func MustNewMapArg(key string, values map[string]string) *MapArg {
|
|||
return a
|
||||
}
|
||||
|
||||
func NewMapArg(key string, values map[string]string) (*MapArg, error) {
|
||||
a := &MapArg{
|
||||
key: key,
|
||||
values: make(map[string]string),
|
||||
func NewKeyValueArg(key string, items []KeyValueArgItem) (*KeyValueArg, error) {
|
||||
a := &KeyValueArg{
|
||||
key: key,
|
||||
// We're creating a copy here because we do not
|
||||
// want to reference to any external source
|
||||
// that can be modified after we've done checks.
|
||||
items: make([]KeyValueArgItem, len(items)),
|
||||
}
|
||||
|
||||
// Preflight arg key/type check.
|
||||
|
|
@ -33,60 +41,71 @@ func NewMapArg(key string, values map[string]string) (*MapArg, error) {
|
|||
return nil, errors.Wrap(err, "validate arg key")
|
||||
}
|
||||
|
||||
for k, v := range values {
|
||||
// The reason why we're making copies here and creating
|
||||
// a whole other copy of the entire map is because maps
|
||||
// are pointers, and we do not want to reference anything
|
||||
// that we will not be able to validate except at this
|
||||
// stage of MapArg creation.
|
||||
k := k
|
||||
v := v
|
||||
for i, item := range items {
|
||||
// We're making a copy here because we don't want to
|
||||
// leave the possibility to modify the value remotely
|
||||
// after the checks are done. Slices are pointers, and
|
||||
// no copies are made when passing a slice is passed
|
||||
// through to a function.
|
||||
item := item
|
||||
|
||||
if len(k) == 0 {
|
||||
return nil, fmt.Errorf("empty map key not allowed")
|
||||
if len(item.Key) == 0 {
|
||||
return nil, fmt.Errorf("empty key not allowed")
|
||||
}
|
||||
|
||||
if len(v) == 1 {
|
||||
if len(item.Value) == 0 {
|
||||
// Values *can* be empty, though. We do not allow them for consistency.
|
||||
return nil, fmt.Errorf("empty map value for key '%v' is not allowed", k)
|
||||
return nil, fmt.Errorf("empty value for key '%v' is not allowed", item.Key)
|
||||
}
|
||||
|
||||
err := validateArgStrValue(k)
|
||||
err := validateArgStrValue(item.Key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "validate map key '%v'", k)
|
||||
return nil, errors.Wrapf(err, "validate key '%v'", item.Key)
|
||||
}
|
||||
|
||||
err = validateArgStrValue(v)
|
||||
err = validateArgStrValue(item.Value)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "validate map value '%v'", v)
|
||||
return nil, errors.Wrapf(err, "validate map value '%v'", item.Value)
|
||||
}
|
||||
|
||||
a.values[k] = v
|
||||
a.items[i] = item
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (a *MapArg) StringKey() string {
|
||||
func (a *KeyValueArg) StringKey() string {
|
||||
return a.key
|
||||
}
|
||||
|
||||
func (a *MapArg) StringValue() string {
|
||||
func (a *KeyValueArg) StringValue() string {
|
||||
sb := new(strings.Builder)
|
||||
for k, v := range a.values {
|
||||
for i, item := range a.items {
|
||||
// We're not validating anything here because
|
||||
// we expect that the keys/values were validated
|
||||
// at the creation of the MapArg.
|
||||
|
||||
sb.WriteString(k)
|
||||
if len(v) > 0 {
|
||||
sb.WriteString("=" + v)
|
||||
if item.Key == "" {
|
||||
// But if for whatever reason it happens that
|
||||
// a key is blank, we skip the entire item because
|
||||
// otherwise it's bad syntax.
|
||||
continue
|
||||
}
|
||||
|
||||
if i != 0 {
|
||||
sb.WriteString(",")
|
||||
}
|
||||
|
||||
sb.WriteString(item.Key)
|
||||
if len(item.Value) > 0 {
|
||||
// Item values can theoretically be empty.
|
||||
sb.WriteString("=" + item.Value)
|
||||
}
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (a *MapArg) ValueType() ArgAcceptedValue {
|
||||
return ArgAcceptedValueMap
|
||||
func (a *KeyValueArg) ValueType() ArgAcceptedValue {
|
||||
return ArgAcceptedValueKeyValue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,5 +23,11 @@ func validateArgStrValue(s string) error {
|
|||
return fmt.Errorf("commas are not allowed")
|
||||
}
|
||||
|
||||
if strings.Contains(s, "\\") {
|
||||
// Backslashes are theoretically allowed, but they rarely work as intended.
|
||||
// For Windows paths, forward slashes should be used.
|
||||
return fmt.Errorf("backslashes are not allowed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue