diff --git a/pkg/vsphere/toolbox/backdoor.go b/pkg/vsphere/toolbox/backdoor.go index c2fef243f6..c6b3101676 100644 --- a/pkg/vsphere/toolbox/backdoor.go +++ b/pkg/vsphere/toolbox/backdoor.go @@ -39,12 +39,7 @@ type backdoorChannel struct { } func (b *backdoorChannel) Start() error { - isVM, err := vmcheck.IsVirtualWorld() - if err != nil { - return err - } - - if !isVM { + if !vmcheck.IsVirtualCPU() { return ErrNotVirtualWorld } diff --git a/pkg/vsphere/toolbox/backdoor_test.go b/pkg/vsphere/toolbox/backdoor_test.go index 7d243f843b..1bc8040d35 100644 --- a/pkg/vsphere/toolbox/backdoor_test.go +++ b/pkg/vsphere/toolbox/backdoor_test.go @@ -30,8 +30,13 @@ func TestBackdoorChannel(t *testing.T) { } for _, f := range funcs { - if err := f(); err != nil { - t.Skip(err.Error()) + err := f() + + if err != nil { + if err == ErrNotVirtualWorld { + t.SkipNow() + } + t.Fatal(err) } } diff --git a/pkg/vsphere/toolbox/guest_info.go b/pkg/vsphere/toolbox/guest_info.go new file mode 100644 index 0000000000..e0187aca20 --- /dev/null +++ b/pkg/vsphere/toolbox/guest_info.go @@ -0,0 +1,181 @@ +// Copyright 2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package toolbox + +import ( + "bytes" + "fmt" + "net" + + "github.com/davecgh/go-xdr/xdr2" +) + +// Defs from: open-vm-tools/lib/guestRpc/nicinfo.x + +type TypedIPAddress struct { + Type int32 + Address []byte +} + +type IPAddressEntry struct { + Address TypedIPAddress + PrefixLength uint32 + Origin *int32 `xdr:"optional"` + Status *int32 `xdr:"optional"` +} + +type InetCidrRouteEntry struct { + Dest TypedIPAddress + PrefixLength uint32 + NextHop *TypedIPAddress `xdr:"optional"` + IfIndex uint32 + Type int32 + Metric uint32 +} + +type DNSConfigInfo struct { + HostName *string `xdr:"optional"` + DomainName *string `xdr:"optional"` + Servers []TypedIPAddress + Search *string `xdr:"optional"` +} + +type WinsConfigInfo struct { + Primary TypedIPAddress + Secondary TypedIPAddress +} + +type DhcpConfigInfo struct { + Enabled bool + Settings string +} + +type GuestNicV3 struct { + MacAddress string + IPs []IPAddressEntry + DNSConfigInfo *DNSConfigInfo `xdr:"optional"` + WinsConfigInfo *WinsConfigInfo `xdr:"optional"` + DhcpConfigInfov4 *DhcpConfigInfo `xdr:"optional"` + DhcpConfigInfov6 *DhcpConfigInfo `xdr:"optional"` +} + +type NicInfoV3 struct { + Nics []GuestNicV3 + Routes []InetCidrRouteEntry + DNSConfigInfo *DNSConfigInfo `xdr:"optional"` + WinsConfigInfo *WinsConfigInfo `xdr:"optional"` + DhcpConfigInfov4 *DhcpConfigInfo `xdr:"optional"` + DhcpConfigInfov6 *DhcpConfigInfo `xdr:"optional"` +} + +type GuestNicInfo struct { + Version int32 + V3 *NicInfoV3 `xdr:"optional"` +} + +func EncodeXDR(val interface{}) ([]byte, error) { + var buf bytes.Buffer + + _, err := xdr.Marshal(&buf, val) + if err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func DecodeXDR(buf []byte, val interface{}) error { + r := bytes.NewReader(buf) + _, err := xdr.Unmarshal(r, val) + return err +} + +func NewGuestNicInfo() *GuestNicInfo { + return &GuestNicInfo{ + Version: 3, + V3: &NicInfoV3{}, + } +} + +func (nic *GuestNicV3) AddIP(addr net.Addr) { + ip, ok := addr.(*net.IPNet) + if !ok { + return + } + + kind := int32(1) // IAT_IPV4 + if ip.IP.To4() == nil { + kind = 2 // IAT_IPV6 + } else { + ip.IP = ip.IP.To4() // convert to 4-byte representation + } + + size, _ := ip.Mask.Size() + + // nicinfo.x defines enum IpAddressStatus, but vmtoolsd only uses IAS_PREFERRED + var status int32 = 1 // IAS_PREFERRED + + e := IPAddressEntry{ + Address: TypedIPAddress{ + Type: kind, + Address: []byte(ip.IP), + }, + PrefixLength: uint32(size), + Status: &status, + } + + nic.IPs = append(nic.IPs, e) +} + +func GuestInfoCommand(kind int, req []byte) []byte { + request := fmt.Sprintf("SetGuestInfo %d ", kind) + return append([]byte(request), req...) +} + +func DefaultGuestNicInfo() *GuestNicInfo { + proto := NewGuestNicInfo() + info := proto.V3 + + ifs, _ := net.Interfaces() + + for _, i := range ifs { + if i.Flags&net.FlagLoopback == net.FlagLoopback { + continue + } + + nic := GuestNicV3{ + MacAddress: i.HardwareAddr.String(), + } + + addrs, _ := i.Addrs() + + for _, addr := range addrs { + nic.AddIP(addr) + } + + info.Nics = append(info.Nics, nic) + } + + return proto +} + +func GuestInfoNicInfoRequest() ([]byte, error) { + r, err := EncodeXDR(DefaultGuestNicInfo()) + if err != nil { + return nil, err + } + + return GuestInfoCommand(9 /*INFO_IPADDRESS_V3*/, r), nil +} diff --git a/pkg/vsphere/toolbox/guest_info_test.go b/pkg/vsphere/toolbox/guest_info_test.go new file mode 100644 index 0000000000..8e8ad1dd9c --- /dev/null +++ b/pkg/vsphere/toolbox/guest_info_test.go @@ -0,0 +1,49 @@ +// Copyright 2017 VMware, Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package toolbox + +import ( + "net" + "reflect" + "testing" +) + +func TestDefaultGuestNicProto(t *testing.T) { + p := DefaultGuestNicInfo() + + info := p.V3 + + for _, nic := range info.Nics { + _, err := net.ParseMAC(nic.MacAddress) + if err != nil { + t.Errorf("invalid MAC %s: %s", nic.MacAddress, err) + } + } + + b, err := EncodeXDR(p) + if err != nil { + t.Fatal(err) + } + + var dp GuestNicInfo + err = DecodeXDR(b, &dp) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(p, &dp) { + t.Error("decode mismatch") + } +} diff --git a/pkg/vsphere/toolbox/service.go b/pkg/vsphere/toolbox/service.go index c40c2817ec..c8ad362099 100644 --- a/pkg/vsphere/toolbox/service.go +++ b/pkg/vsphere/toolbox/service.go @@ -233,6 +233,8 @@ func (s *Service) SetOption(args []byte) ([]byte, error) { if err != nil { return nil, err } + + s.SendGuestInfo() } default: // TODO: handle other options... @@ -268,3 +270,21 @@ func (s *Service) CapabilitiesRegister([]byte) ([]byte, error) { return nil, nil } + +func (s *Service) SendGuestInfo() { + info := []func() ([]byte, error){ + GuestInfoNicInfoRequest, + } + + for i, r := range info { + b, err := r() + + if err == nil { + _, err = s.out.Request(b) + } + + if err != nil { + log.Printf("SendGuestInfo %d: %s", i, err) + } + } +} diff --git a/pkg/vsphere/toolbox/service_test.go b/pkg/vsphere/toolbox/service_test.go index e285715122..5d09010797 100644 --- a/pkg/vsphere/toolbox/service_test.go +++ b/pkg/vsphere/toolbox/service_test.go @@ -216,6 +216,7 @@ func TestServiceErrors(t *testing.T) { out.reply, rpciERR, rpciOK, + rpciOK, append(rpciOK, foo...), rpciERR, ) diff --git a/pkg/vsphere/toolbox/toolbox-test.sh b/pkg/vsphere/toolbox/toolbox-test.sh index 92961f0241..6474596509 100755 --- a/pkg/vsphere/toolbox/toolbox-test.sh +++ b/pkg/vsphere/toolbox/toolbox-test.sh @@ -125,7 +125,7 @@ scp "${opts[@]}" "$GOPATH"/bin/toolbox{,.test} "core@${ip}:" if [ -n "$test" ] ; then echo "Running toolbox tests..." - ssh "${opts[@]}" "core@${ip}" sudo ./toolbox.test -test.v -test.run TestServiceRunESX -toolbox.testesx \ + ssh "${opts[@]}" "core@${ip}" ./toolbox.test -test.v -test.run TestServiceRunESX -toolbox.testesx \ -toolbox.testpid="$$" -toolbox.powerState="$state" & echo "Waiting for VM ip from toolbox..." diff --git a/tests/test-cases/Group8-vSphere-Integration/8-01-GuestTools.robot b/tests/test-cases/Group8-vSphere-Integration/8-01-GuestTools.robot index 4a8aadc7e2..67ff35cebb 100644 --- a/tests/test-cases/Group8-vSphere-Integration/8-01-GuestTools.robot +++ b/tests/test-cases/Group8-vSphere-Integration/8-01-GuestTools.robot @@ -24,8 +24,11 @@ Verify container VM guest IP is reported ${name}= Generate Random String 15 ${rc} ${id}= Run And Return Rc And Output docker %{VCH-PARAMS} run --name ${name} -d busybox /bin/top Should Be Equal As Integers ${rc} 0 - ${rc} ${output}= Run And Return Rc And Output govc vm.ip ${name}-* + ${rc} ${ip}= Run And Return Rc And Output govc vm.ip ${name}-* Should Be Equal As Integers ${rc} 0 + ${rc} ${output}= Run And Return Rc And Output govc vm.info -json ${name}-* | jq -r .VirtualMachines[].Guest.Net[].IpAddress[] + Should Be Equal As Integers ${rc} 0 + Should Contain ${output} ${ip} Stop container VM using guest shutdown ${rc}= Run And Return Rc docker %{VCH-PARAMS} pull busybox diff --git a/vendor/github.com/davecgh/go-xdr/LICENSE b/vendor/github.com/davecgh/go-xdr/LICENSE new file mode 100644 index 0000000000..0cc3543cef --- /dev/null +++ b/vendor/github.com/davecgh/go-xdr/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2012-2014 Dave Collins + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/davecgh/go-xdr/xdr2/decode.go b/vendor/github.com/davecgh/go-xdr/xdr2/decode.go index 494dae6461..6f37f76b7f 100644 --- a/vendor/github.com/davecgh/go-xdr/xdr2/decode.go +++ b/vendor/github.com/davecgh/go-xdr/xdr2/decode.go @@ -21,6 +21,7 @@ import ( "io" "math" "reflect" + "strconv" "time" ) @@ -507,6 +508,7 @@ func (d *Decoder) decodeArray(v reflect.Value, ignoreOpaque bool) (int, error) { // XDR encoded elements in the order of their declaration in the struct func (d *Decoder) decodeStruct(v reflect.Value) (int, error) { var n int + var union string vt := v.Type() for i := 0; i < v.NumField(); i++ { // Skip unexported fields. @@ -515,13 +517,36 @@ func (d *Decoder) decodeStruct(v reflect.Value) (int, error) { continue } + vf := v.Field(i) + tag := parseTag(vtf.Tag) + + // RFC Section 4.19 - Optional data + if tag.Get("optional") == "true" { + if vf.Type().Kind() != reflect.Ptr { + msg := fmt.Sprintf("optional must be a pointer, not '%v'", + vf.Type().String()) + err := unmarshalError("decodeStruct", ErrBadOptional, + msg, nil, nil) + return n, err + } + + hasopt, n2, err := d.DecodeBool() + n += n2 + if err != nil { + return n, err + } + if !hasopt { + continue + } + } + // Indirect through pointers allocating them as needed and // ensure the field is settable. - vf := v.Field(i) vf, err := d.indirect(vf) if err != nil { return n, err } + if !vf.CanSet() { msg := fmt.Sprintf("can't decode to unsettable '%v'", vf.Type().String()) @@ -532,8 +557,7 @@ func (d *Decoder) decodeStruct(v reflect.Value) (int, error) { // Handle non-opaque data to []uint8 and [#]uint8 based on // struct tag. - tag := vtf.Tag.Get("xdropaque") - if tag == "false" { + if tag.Get("opaque") == "false" { switch vf.Kind() { case reflect.Slice: n2, err := d.decodeArray(vf, true) @@ -553,25 +577,46 @@ func (d *Decoder) decodeStruct(v reflect.Value) (int, error) { } } + if union != "" { + ucase := tag.Get("unioncase") + if ucase != "" && ucase != union { + continue + } + } + // Decode each struct field. n2, err := d.decode(vf) n += n2 if err != nil { return n, err } + + if tag.Get("union") == "true" { + if vf.Type().ConvertibleTo(reflect.TypeOf(0)) { + union = strconv.Itoa(int(vf.Convert(reflect.TypeOf(0)).Int())) + } else if vf.Kind() == reflect.Bool { + if vf.Bool() { + union = "1" + } else { + union = "0" + } + } else { + msg := fmt.Sprintf("type '%s' is not valid", vf.Kind().String()) + return n, unmarshalError("decodeStruct", ErrBadDiscriminant, msg, nil, nil) + } + } + } return n, nil } -// RFC Section 4.15 - Discriminated Union // RFC Section 4.16 - Void // RFC Section 4.17 - Constant // RFC Section 4.18 - Typedef // RFC Section 4.19 - Optional data // RFC Sections 4.15 though 4.19 only apply to the data specification language -// which is not implemented by this package. In the case of discriminated -// unions, struct tags are used to perform a similar function. +// which is not implemented by this package. // decodeMap treats the next bytes as an XDR encoded variable array of 2-element // structures whose fields are of the same type as the map keys and elements diff --git a/vendor/github.com/davecgh/go-xdr/xdr2/doc.go b/vendor/github.com/davecgh/go-xdr/xdr2/doc.go index 8823d62f36..1904d2b8ef 100644 --- a/vendor/github.com/davecgh/go-xdr/xdr2/doc.go +++ b/vendor/github.com/davecgh/go-xdr/xdr2/doc.go @@ -66,14 +66,15 @@ and Unmarshal functions has specific details of how the mapping proceeds. [#]byte <-> XDR Fixed-Length Opaque Data [] <-> XDR Variable-Length Array [#] <-> XDR Fixed-Length Array - struct <-> XDR Structure + * <-> XDR Optional data (when marked with struct tag `xdr:"optional"`) + struct <-> XDR Structure or Discriminated Unions map <-> XDR Variable-Length Array of two-element XDR Structures time.Time <-> XDR String encoded with RFC3339 nanosecond precision Notes and Limitations: * Automatic marshalling and unmarshalling of variable and fixed-length - arrays of uint8s require a special struct tag `xdropaque:"false"` + arrays of uint8s require a special struct tag `xdr:"opaque=false"` since byte slices and byte arrays are assumed to be opaque data and byte is a Go alias for uint8 thus indistinguishable under reflection * Channel, complex, and function types cannot be encoded @@ -159,6 +160,40 @@ manually decode XDR primitives for complex scenarios where automatic reflection-based decoding won't work. The included examples provide a sample of manual usage via a Decoder. + +Discriminated Unions + +Discriminated unions are marshalled via Go structs, using special struct tags +to mark the discriminant and the different cases. For instance: + + type ReturnValue struct { + Status int `xdr:"union"` + StatusOk struct { + Width int + Height int + } `xdr:"unioncase=0"` + StatusError struct { + ErrMsg string + } `xdr:"unioncase=-1"` + } + +The Status field is the discriminant of the union, and is always serialized; +if its value is 0, the StatusOK struct is serialized while the StatusErr struct +is ignored; if its value is -1, the opposite happens. If the value is different +from both 0 and -1, only the Status field is serialized. Any additional field +not marked with unioncase is always serialized as normal. + +You are not forced to use sub-structures; for instance, the following is also +valid: + + type ReturnValue struct { + Status int `xdr:"union"` + Width int `xdr:"unioncase=0"` + Height int `xdr:"unioncase=0"` + ErrMsg string `xdr:"unioncase=-1"` + } + + Errors All errors are either of type UnmarshalError or MarshalError. Both provide diff --git a/vendor/github.com/davecgh/go-xdr/xdr2/encode.go b/vendor/github.com/davecgh/go-xdr/xdr2/encode.go index 7bac2681d7..73a2ff00b6 100644 --- a/vendor/github.com/davecgh/go-xdr/xdr2/encode.go +++ b/vendor/github.com/davecgh/go-xdr/xdr2/encode.go @@ -21,6 +21,7 @@ import ( "io" "math" "reflect" + "strconv" "time" ) @@ -440,6 +441,7 @@ func (enc *Encoder) encodeArray(v reflect.Value, ignoreOpaque bool) (int, error) // XDR encoded elements in the order of their declaration in the struct func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) { var n int + var union string vt := v.Type() for i := 0; i < v.NumField(); i++ { // Skip unexported fields and indirect through pointers. @@ -447,12 +449,35 @@ func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) { if vtf.PkgPath != "" { continue } + vf := v.Field(i) + tag := parseTag(vtf.Tag) + + // RFC Section 4.19 - Optional data + if tag.Get("optional") == "true" { + if vf.Type().Kind() != reflect.Ptr { + msg := fmt.Sprintf("optional must be a pointer, not '%v'", + vf.Type().String()) + err := marshalError("encodeStruct", ErrBadOptional, + msg, nil, nil) + return n, err + } + + hasopt := !vf.IsNil() + n2, err := enc.EncodeBool(hasopt) + n += n2 + if err != nil { + return n, err + } + if !hasopt { + continue + } + } + vf = enc.indirect(vf) // Handle non-opaque data to []uint8 and [#]uint8 based on struct tag. - tag := vtf.Tag.Get("xdropaque") - if tag == "false" { + if tag.Get("opaque") == "false" { switch vf.Kind() { case reflect.Slice: n2, err := enc.encodeArray(vf, true) @@ -472,6 +497,32 @@ func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) { } } + // RFC Section 4.15 - Discriminated Union + // The tag option "union" marks the discriminant in the struct; the tag + // option "unioncase=N" marks a struct field that is only serialized + // when the discriminant has the specified value. + if tag.Get("union") == "true" { + if vf.Type().ConvertibleTo(reflect.TypeOf(0)) { + union = strconv.Itoa(int(vf.Convert(reflect.TypeOf(0)).Int())) + } else if vf.Kind() == reflect.Bool { + if vf.Bool() { + union = "1" + } else { + union = "0" + } + } else { + msg := fmt.Sprintf("type '%s' is not valid", vf.Kind().String()) + return n, marshalError("encodeStruct", ErrBadDiscriminant, msg, nil, nil) + } + } + + if union != "" { + ucase := tag.Get("unioncase") + if ucase != "" && ucase != union { + continue + } + } + // Encode each struct field. n2, err := enc.encode(vf) n += n2 @@ -483,14 +534,12 @@ func (enc *Encoder) encodeStruct(v reflect.Value) (int, error) { return n, nil } -// RFC Section 4.15 - Discriminated Union // RFC Section 4.16 - Void // RFC Section 4.17 - Constant // RFC Section 4.18 - Typedef // RFC Section 4.19 - Optional data -// RFC Sections 4.15 though 4.19 only apply to the data specification language -// which is not implemented by this package. In the case of discriminated -// unions, struct tags are used to perform a similar function. +// RFC Sections 4.16 though 4.19 only apply to the data specification language +// which is not implemented by this package. // encodeMap treats the map represented by the passed reflection value as a // variable-length array of 2-element structures whose fields are of the same diff --git a/vendor/github.com/davecgh/go-xdr/xdr2/error.go b/vendor/github.com/davecgh/go-xdr/xdr2/error.go index 42079ad354..8c1f3aec4c 100644 --- a/vendor/github.com/davecgh/go-xdr/xdr2/error.go +++ b/vendor/github.com/davecgh/go-xdr/xdr2/error.go @@ -61,6 +61,14 @@ const ( // RFC3339 formatted time value. The actual underlying error will be // available via the Err field of the UnmarshalError struct. ErrParseTime + + // ErrBadDiscriminant indicates that a non-integer field of a struct + // was marked as a union discriminant through a struct tag. + ErrBadDiscriminant + + // ErrBadOptional indicates that a non-pointer field of a struct + // was marked as an optional-data. + ErrBadOptional ) // Map of ErrorCode values back to their constant names for pretty printing. @@ -73,6 +81,8 @@ var errorCodeStrings = map[ErrorCode]string{ ErrNilInterface: "ErrNilInterface", ErrIO: "ErrIO", ErrParseTime: "ErrParseTime", + ErrBadDiscriminant: "ErrBadDiscriminant", + ErrBadOptional: "ErrBadOptional", } // String returns the ErrorCode as a human-readable name. diff --git a/vendor/github.com/davecgh/go-xdr/xdr2/tag.go b/vendor/github.com/davecgh/go-xdr/xdr2/tag.go new file mode 100644 index 0000000000..7b5fe24b4a --- /dev/null +++ b/vendor/github.com/davecgh/go-xdr/xdr2/tag.go @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015-2017 Giovanni Bajo + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package xdr + +import ( + "reflect" + "strings" +) + +// xdrtag represents a XDR struct tag, identified by the name "xdr:". +// The value of the tag is a string that is parsed as a comma-separated +// list of =-separated key-value options. If an option has no value, +// "true" is assumed to be the default value. +// +// For instance: +// +// `xdr:"foo,bar=2,baz=false" +// +// After parsing this tag, Get("foo") will return "true", Get("bar") +// will return "2", and Get("baz") will return "false". +type xdrtag string + +// parseTag extracts a xdrtag from the original reflect.StructTag as found in +// in the struct field. If the tag was not specified, an empty strtag is +// returned. +func parseTag(tag reflect.StructTag) xdrtag { + t := tag.Get("xdr") + // Handle backward compatibility with the previous "xdropaque" + // tag which is now deprecated. + if tag.Get("xdropaque") == "false" { + if t == "" { + t = "," + } + t += ",opaque=false" + } + return xdrtag(t) +} + +// Get returns the value for the specified option. If the option is not +// present in the tag, an empty string is returned. If the option is +// present but has no value, the string "true" is returned as default value. +func (t xdrtag) Get(opt string) string { + tag := string(t) + for tag != "" { + var next string + i := strings.Index(tag, ",") + if i >= 0 { + tag, next = tag[:i], tag[i+1:] + } + if tag == opt { + return "true" + } + if len(tag) > len(opt) && tag[:len(opt)] == opt && tag[len(opt)] == '=' { + return tag[len(opt)+1:] + } + tag = next + } + return "" +} diff --git a/vendor/manifest b/vendor/manifest index aa8380034f..3b2b28d6aa 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -248,10 +248,10 @@ }, { "importpath": "github.com/davecgh/go-xdr/xdr2", - "repository": "https://github.com/davecgh/go-xdr", + "repository": "https://github.com/rasky/go-xdr", "vcs": "git", - "revision": "e6a2ba005892b6a5b27cb5352f64c2e96942dd28", - "branch": "master", + "revision": "4930550ba2e22f87187498acfd78348b15f4e7a8", + "branch": "improvements", "path": "/xdr2", "notests": true },