gopkg.in/libvirt/libvirt-go-xml.v7@v7.4.0/network.go (about)

     1  /*
     2   * This file is part of the libvirt-go-xml project
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    20   * THE SOFTWARE.
    21   *
    22   * Copyright (C) 2017 Lian Duan <blazeblue@gmail.com>
    23   *
    24   */
    25  
    26  package libvirtxml
    27  
    28  import (
    29  	"encoding/xml"
    30  )
    31  
    32  type NetworkBridge struct {
    33  	Name            string `xml:"name,attr,omitempty"`
    34  	STP             string `xml:"stp,attr,omitempty"`
    35  	Delay           string `xml:"delay,attr,omitempty"`
    36  	MACTableManager string `xml:"macTableManager,attr,omitempty"`
    37  	Zone            string `xml:"zone,attr,omitempty"`
    38  }
    39  
    40  type NetworkVirtualPort struct {
    41  	Params *NetworkVirtualPortParams `xml:"parameters"`
    42  }
    43  
    44  type NetworkVirtualPortParams struct {
    45  	Any          *NetworkVirtualPortParamsAny          `xml:"-"`
    46  	VEPA8021QBG  *NetworkVirtualPortParamsVEPA8021QBG  `xml:"-"`
    47  	VNTag8011QBH *NetworkVirtualPortParamsVNTag8021QBH `xml:"-"`
    48  	OpenVSwitch  *NetworkVirtualPortParamsOpenVSwitch  `xml:"-"`
    49  	MidoNet      *NetworkVirtualPortParamsMidoNet      `xml:"-"`
    50  }
    51  
    52  type NetworkVirtualPortParamsAny struct {
    53  	ManagerID     *uint  `xml:"managerid,attr"`
    54  	TypeID        *uint  `xml:"typeid,attr"`
    55  	TypeIDVersion *uint  `xml:"typeidversion,attr"`
    56  	InstanceID    string `xml:"instanceid,attr,omitempty"`
    57  	ProfileID     string `xml:"profileid,attr,omitempty"`
    58  	InterfaceID   string `xml:"interfaceid,attr,omitempty"`
    59  }
    60  
    61  type NetworkVirtualPortParamsVEPA8021QBG struct {
    62  	ManagerID     *uint  `xml:"managerid,attr"`
    63  	TypeID        *uint  `xml:"typeid,attr"`
    64  	TypeIDVersion *uint  `xml:"typeidversion,attr"`
    65  	InstanceID    string `xml:"instanceid,attr,omitempty"`
    66  }
    67  
    68  type NetworkVirtualPortParamsVNTag8021QBH struct {
    69  	ProfileID string `xml:"profileid,attr,omitempty"`
    70  }
    71  
    72  type NetworkVirtualPortParamsOpenVSwitch struct {
    73  	InterfaceID string `xml:"interfaceid,attr,omitempty"`
    74  	ProfileID   string `xml:"profileid,attr,omitempty"`
    75  }
    76  
    77  type NetworkVirtualPortParamsMidoNet struct {
    78  	InterfaceID string `xml:"interfaceid,attr,omitempty"`
    79  }
    80  
    81  type NetworkDomain struct {
    82  	Name      string `xml:"name,attr,omitempty"`
    83  	LocalOnly string `xml:"localOnly,attr,omitempty"`
    84  }
    85  
    86  type NetworkForwardNATAddress struct {
    87  	Start string `xml:"start,attr"`
    88  	End   string `xml:"end,attr"`
    89  }
    90  
    91  type NetworkForwardNATPort struct {
    92  	Start uint `xml:"start,attr"`
    93  	End   uint `xml:"end,attr"`
    94  }
    95  
    96  type NetworkForwardNAT struct {
    97  	IPv6      string                     `xml:"ipv6,attr,omitempty"`
    98  	Addresses []NetworkForwardNATAddress `xml:"address"`
    99  	Ports     []NetworkForwardNATPort    `xml:"port"`
   100  }
   101  
   102  type NetworkForward struct {
   103  	Mode       string                    `xml:"mode,attr,omitempty"`
   104  	Dev        string                    `xml:"dev,attr,omitempty"`
   105  	Managed    string                    `xml:"managed,attr,omitempty"`
   106  	Driver     *NetworkForwardDriver     `xml:"driver"`
   107  	PFs        []NetworkForwardPF        `xml:"pf"`
   108  	NAT        *NetworkForwardNAT        `xml:"nat"`
   109  	Interfaces []NetworkForwardInterface `xml:"interface"`
   110  	Addresses  []NetworkForwardAddress   `xml:"address"`
   111  }
   112  
   113  type NetworkForwardDriver struct {
   114  	Name string `xml:"name,attr"`
   115  }
   116  
   117  type NetworkForwardPF struct {
   118  	Dev string `xml:"dev,attr"`
   119  }
   120  
   121  type NetworkForwardAddress struct {
   122  	PCI *NetworkForwardAddressPCI `xml:"-"`
   123  }
   124  
   125  type NetworkForwardAddressPCI struct {
   126  	Domain   *uint `xml:"domain,attr"`
   127  	Bus      *uint `xml:"bus,attr"`
   128  	Slot     *uint `xml:"slot,attr"`
   129  	Function *uint `xml:"function,attr"`
   130  }
   131  
   132  type NetworkForwardInterface struct {
   133  	XMLName xml.Name `xml:"interface"`
   134  	Dev     string   `xml:"dev,attr,omitempty"`
   135  }
   136  
   137  type NetworkMAC struct {
   138  	Address string `xml:"address,attr,omitempty"`
   139  }
   140  
   141  type NetworkDHCPRange struct {
   142  	XMLName xml.Name          `xml:"range"`
   143  	Start   string            `xml:"start,attr,omitempty"`
   144  	End     string            `xml:"end,attr,omitempty"`
   145  	Lease   *NetworkDHCPLease `xml:"lease"`
   146  }
   147  
   148  type NetworkDHCPLease struct {
   149  	Expiry uint   `xml:"expiry,attr"`
   150  	Unit   string `xml:"unit,attr,omitempty"`
   151  }
   152  
   153  type NetworkDHCPHost struct {
   154  	XMLName xml.Name          `xml:"host"`
   155  	ID      string            `xml:"id,attr,omitempty"`
   156  	MAC     string            `xml:"mac,attr,omitempty"`
   157  	Name    string            `xml:"name,attr,omitempty"`
   158  	IP      string            `xml:"ip,attr,omitempty"`
   159  	Lease   *NetworkDHCPLease `xml:"lease"`
   160  }
   161  
   162  type NetworkBootp struct {
   163  	File   string `xml:"file,attr,omitempty"`
   164  	Server string `xml:"server,attr,omitempty"`
   165  }
   166  
   167  type NetworkDHCP struct {
   168  	Ranges []NetworkDHCPRange `xml:"range"`
   169  	Hosts  []NetworkDHCPHost  `xml:"host"`
   170  	Bootp  []NetworkBootp     `xml:"bootp"`
   171  }
   172  
   173  type NetworkIP struct {
   174  	Address  string       `xml:"address,attr,omitempty"`
   175  	Family   string       `xml:"family,attr,omitempty"`
   176  	Netmask  string       `xml:"netmask,attr,omitempty"`
   177  	Prefix   uint         `xml:"prefix,attr,omitempty"`
   178  	LocalPtr string       `xml:"localPtr,attr,omitempty"`
   179  	DHCP     *NetworkDHCP `xml:"dhcp"`
   180  	TFTP     *NetworkTFTP `xml:"tftp"`
   181  }
   182  
   183  type NetworkTFTP struct {
   184  	Root string `xml:"root,attr,omitempty"`
   185  }
   186  
   187  type NetworkRoute struct {
   188  	Family  string `xml:"family,attr,omitempty"`
   189  	Address string `xml:"address,attr,omitempty"`
   190  	Netmask string `xml:"netmask,attr,omitempty"`
   191  	Prefix  uint   `xml:"prefix,attr,omitempty"`
   192  	Gateway string `xml:"gateway,attr,omitempty"`
   193  	Metric  string `xml:"metric,attr,omitempty"`
   194  }
   195  
   196  type NetworkDNSForwarder struct {
   197  	Domain string `xml:"domain,attr,omitempty"`
   198  	Addr   string `xml:"addr,attr,omitempty"`
   199  }
   200  
   201  type NetworkDNSTXT struct {
   202  	XMLName xml.Name `xml:"txt"`
   203  	Name    string   `xml:"name,attr"`
   204  	Value   string   `xml:"value,attr"`
   205  }
   206  
   207  type NetworkDNSHostHostname struct {
   208  	Hostname string `xml:",chardata"`
   209  }
   210  
   211  type NetworkDNSHost struct {
   212  	XMLName   xml.Name                 `xml:"host"`
   213  	IP        string                   `xml:"ip,attr"`
   214  	Hostnames []NetworkDNSHostHostname `xml:"hostname"`
   215  }
   216  
   217  type NetworkDNSSRV struct {
   218  	XMLName  xml.Name `xml:"srv"`
   219  	Service  string   `xml:"service,attr,omitempty"`
   220  	Protocol string   `xml:"protocol,attr,omitempty"`
   221  	Target   string   `xml:"target,attr,omitempty"`
   222  	Port     uint     `xml:"port,attr,omitempty"`
   223  	Priority uint     `xml:"priority,attr,omitempty"`
   224  	Weight   uint     `xml:"weight,attr,omitempty"`
   225  	Domain   string   `xml:"domain,attr,omitempty"`
   226  }
   227  
   228  type NetworkDNS struct {
   229  	Enable            string                `xml:"enable,attr,omitempty"`
   230  	ForwardPlainNames string                `xml:"forwardPlainNames,attr,omitempty"`
   231  	Forwarders        []NetworkDNSForwarder `xml:"forwarder"`
   232  	TXTs              []NetworkDNSTXT       `xml:"txt"`
   233  	Host              []NetworkDNSHost      `xml:"host"`
   234  	SRVs              []NetworkDNSSRV       `xml:"srv"`
   235  }
   236  
   237  type NetworkMetadata struct {
   238  	XML string `xml:",innerxml"`
   239  }
   240  
   241  type NetworkMTU struct {
   242  	Size uint `xml:"size,attr"`
   243  }
   244  
   245  type Network struct {
   246  	XMLName             xml.Name            `xml:"network"`
   247  	IPv6                string              `xml:"ipv6,attr,omitempty"`
   248  	TrustGuestRxFilters string              `xml:"trustGuestRxFilters,attr,omitempty"`
   249  	Name                string              `xml:"name,omitempty"`
   250  	UUID                string              `xml:"uuid,omitempty"`
   251  	Metadata            *NetworkMetadata    `xml:"metadata"`
   252  	Forward             *NetworkForward     `xml:"forward"`
   253  	Bridge              *NetworkBridge      `xml:"bridge"`
   254  	MTU                 *NetworkMTU         `xml:"mtu"`
   255  	MAC                 *NetworkMAC         `xml:"mac"`
   256  	Domain              *NetworkDomain      `xml:"domain"`
   257  	DNS                 *NetworkDNS         `xml:"dns"`
   258  	VLAN                *NetworkVLAN        `xml:"vlan"`
   259  	Bandwidth           *NetworkBandwidth   `xml:"bandwidth"`
   260  	PortOptions         *NetworkPortOptions `xml:"port"`
   261  	IPs                 []NetworkIP         `xml:"ip"`
   262  	Routes              []NetworkRoute      `xml:"route"`
   263  	VirtualPort         *NetworkVirtualPort `xml:"virtualport"`
   264  	PortGroups          []NetworkPortGroup  `xml:"portgroup"`
   265  
   266  	DnsmasqOptions *NetworkDnsmasqOptions
   267  }
   268  
   269  type NetworkPortOptions struct {
   270  	Isolated string `xml:"isolated,attr,omitempty"`
   271  }
   272  
   273  type NetworkPortGroup struct {
   274  	XMLName             xml.Name            `xml:"portgroup"`
   275  	Name                string              `xml:"name,attr,omitempty"`
   276  	Default             string              `xml:"default,attr,omitempty"`
   277  	TrustGuestRxFilters string              `xml:"trustGuestRxFilters,attr,omitempty"`
   278  	VLAN                *NetworkVLAN        `xml:"vlan"`
   279  	VirtualPort         *NetworkVirtualPort `xml:"virtualport"`
   280  }
   281  
   282  type NetworkVLAN struct {
   283  	Trunk string           `xml:"trunk,attr,omitempty"`
   284  	Tags  []NetworkVLANTag `xml:"tag"`
   285  }
   286  
   287  type NetworkVLANTag struct {
   288  	ID         uint   `xml:"id,attr"`
   289  	NativeMode string `xml:"nativeMode,attr,omitempty"`
   290  }
   291  
   292  type NetworkBandwidthParams struct {
   293  	Average *uint `xml:"average,attr"`
   294  	Peak    *uint `xml:"peak,attr"`
   295  	Burst   *uint `xml:"burst,attr"`
   296  	Floor   *uint `xml:"floor,attr"`
   297  }
   298  
   299  type NetworkBandwidth struct {
   300  	ClassID  uint                    `xml:"classID,attr,omitempty"`
   301  	Inbound  *NetworkBandwidthParams `xml:"inbound"`
   302  	Outbound *NetworkBandwidthParams `xml:"outbound"`
   303  }
   304  
   305  type NetworkDnsmasqOptions struct {
   306  	XMLName xml.Name               `xml:"http://libvirt.org/schemas/network/dnsmasq/1.0 options"`
   307  	Option  []NetworkDnsmasqOption `xml:"option"`
   308  }
   309  
   310  type NetworkDnsmasqOption struct {
   311  	Value string `xml:"value,attr"`
   312  }
   313  
   314  func (a *NetworkVirtualPortParams) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   315  	start.Name.Local = "parameters"
   316  	if a.Any != nil {
   317  		return e.EncodeElement(a.Any, start)
   318  	} else if a.VEPA8021QBG != nil {
   319  		return e.EncodeElement(a.VEPA8021QBG, start)
   320  	} else if a.VNTag8011QBH != nil {
   321  		return e.EncodeElement(a.VNTag8011QBH, start)
   322  	} else if a.OpenVSwitch != nil {
   323  		return e.EncodeElement(a.OpenVSwitch, start)
   324  	} else if a.MidoNet != nil {
   325  		return e.EncodeElement(a.MidoNet, start)
   326  	}
   327  	return nil
   328  }
   329  
   330  func (a *NetworkVirtualPortParams) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   331  	if a.Any != nil {
   332  		return d.DecodeElement(a.Any, &start)
   333  	} else if a.VEPA8021QBG != nil {
   334  		return d.DecodeElement(a.VEPA8021QBG, &start)
   335  	} else if a.VNTag8011QBH != nil {
   336  		return d.DecodeElement(a.VNTag8011QBH, &start)
   337  	} else if a.OpenVSwitch != nil {
   338  		return d.DecodeElement(a.OpenVSwitch, &start)
   339  	} else if a.MidoNet != nil {
   340  		return d.DecodeElement(a.MidoNet, &start)
   341  	}
   342  	return nil
   343  }
   344  
   345  type networkVirtualPort NetworkVirtualPort
   346  
   347  func (a *NetworkVirtualPort) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   348  	start.Name.Local = "virtualport"
   349  	if a.Params != nil {
   350  		if a.Params.Any != nil {
   351  			/* no type attr wanted */
   352  		} else if a.Params.VEPA8021QBG != nil {
   353  			start.Attr = append(start.Attr, xml.Attr{
   354  				xml.Name{Local: "type"}, "802.1Qbg",
   355  			})
   356  		} else if a.Params.VNTag8011QBH != nil {
   357  			start.Attr = append(start.Attr, xml.Attr{
   358  				xml.Name{Local: "type"}, "802.1Qbh",
   359  			})
   360  		} else if a.Params.OpenVSwitch != nil {
   361  			start.Attr = append(start.Attr, xml.Attr{
   362  				xml.Name{Local: "type"}, "openvswitch",
   363  			})
   364  		} else if a.Params.MidoNet != nil {
   365  			start.Attr = append(start.Attr, xml.Attr{
   366  				xml.Name{Local: "type"}, "midonet",
   367  			})
   368  		}
   369  	}
   370  	vp := networkVirtualPort(*a)
   371  	return e.EncodeElement(&vp, start)
   372  }
   373  
   374  func (a *NetworkVirtualPort) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   375  	typ, ok := getAttr(start.Attr, "type")
   376  	a.Params = &NetworkVirtualPortParams{}
   377  	if !ok {
   378  		var any NetworkVirtualPortParamsAny
   379  		a.Params.Any = &any
   380  	} else if typ == "802.1Qbg" {
   381  		var vepa NetworkVirtualPortParamsVEPA8021QBG
   382  		a.Params.VEPA8021QBG = &vepa
   383  	} else if typ == "802.1Qbh" {
   384  		var vntag NetworkVirtualPortParamsVNTag8021QBH
   385  		a.Params.VNTag8011QBH = &vntag
   386  	} else if typ == "openvswitch" {
   387  		var ovs NetworkVirtualPortParamsOpenVSwitch
   388  		a.Params.OpenVSwitch = &ovs
   389  	} else if typ == "midonet" {
   390  		var mido NetworkVirtualPortParamsMidoNet
   391  		a.Params.MidoNet = &mido
   392  	}
   393  
   394  	vp := networkVirtualPort(*a)
   395  	err := d.DecodeElement(&vp, &start)
   396  	if err != nil {
   397  		return err
   398  	}
   399  	*a = NetworkVirtualPort(vp)
   400  	return nil
   401  }
   402  
   403  func (a *NetworkForwardAddressPCI) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   404  	marshalUintAttr(&start, "domain", a.Domain, "0x%04x")
   405  	marshalUintAttr(&start, "bus", a.Bus, "0x%02x")
   406  	marshalUintAttr(&start, "slot", a.Slot, "0x%02x")
   407  	marshalUintAttr(&start, "function", a.Function, "0x%x")
   408  	e.EncodeToken(start)
   409  	e.EncodeToken(start.End())
   410  	return nil
   411  }
   412  
   413  func (a *NetworkForwardAddressPCI) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   414  	for _, attr := range start.Attr {
   415  		if attr.Name.Local == "domain" {
   416  			if err := unmarshalUintAttr(attr.Value, &a.Domain, 0); err != nil {
   417  				return err
   418  			}
   419  		} else if attr.Name.Local == "bus" {
   420  			if err := unmarshalUintAttr(attr.Value, &a.Bus, 0); err != nil {
   421  				return err
   422  			}
   423  		} else if attr.Name.Local == "slot" {
   424  			if err := unmarshalUintAttr(attr.Value, &a.Slot, 0); err != nil {
   425  				return err
   426  			}
   427  		} else if attr.Name.Local == "function" {
   428  			if err := unmarshalUintAttr(attr.Value, &a.Function, 0); err != nil {
   429  				return err
   430  			}
   431  		}
   432  	}
   433  	d.Skip()
   434  	return nil
   435  }
   436  
   437  func (a *NetworkForwardAddress) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   438  	if a.PCI != nil {
   439  		start.Attr = append(start.Attr, xml.Attr{
   440  			xml.Name{Local: "type"}, "pci",
   441  		})
   442  		return e.EncodeElement(a.PCI, start)
   443  	} else {
   444  		return nil
   445  	}
   446  }
   447  
   448  func (a *NetworkForwardAddress) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   449  	var typ string
   450  	for _, attr := range start.Attr {
   451  		if attr.Name.Local == "type" {
   452  			typ = attr.Value
   453  			break
   454  		}
   455  	}
   456  	if typ == "" {
   457  		d.Skip()
   458  		return nil
   459  	}
   460  
   461  	if typ == "pci" {
   462  		a.PCI = &NetworkForwardAddressPCI{}
   463  		return d.DecodeElement(a.PCI, &start)
   464  	}
   465  
   466  	return nil
   467  }
   468  
   469  func (s *NetworkDHCPHost) Unmarshal(doc string) error {
   470  	return xml.Unmarshal([]byte(doc), s)
   471  }
   472  
   473  func (s *NetworkDHCPHost) Marshal() (string, error) {
   474  	doc, err := xml.MarshalIndent(s, "", "  ")
   475  	if err != nil {
   476  		return "", err
   477  	}
   478  	return string(doc), nil
   479  }
   480  
   481  func (s *NetworkDNSHost) Unmarshal(doc string) error {
   482  	return xml.Unmarshal([]byte(doc), s)
   483  }
   484  
   485  func (s *NetworkDNSHost) Marshal() (string, error) {
   486  	doc, err := xml.MarshalIndent(s, "", "  ")
   487  	if err != nil {
   488  		return "", err
   489  	}
   490  	return string(doc), nil
   491  }
   492  
   493  func (s *NetworkPortGroup) Unmarshal(doc string) error {
   494  	return xml.Unmarshal([]byte(doc), s)
   495  }
   496  
   497  func (s *NetworkPortGroup) Marshal() (string, error) {
   498  	doc, err := xml.MarshalIndent(s, "", "  ")
   499  	if err != nil {
   500  		return "", err
   501  	}
   502  	return string(doc), nil
   503  }
   504  
   505  func (s *NetworkDNSTXT) Unmarshal(doc string) error {
   506  	return xml.Unmarshal([]byte(doc), s)
   507  }
   508  
   509  func (s *NetworkDNSTXT) Marshal() (string, error) {
   510  	doc, err := xml.MarshalIndent(s, "", "  ")
   511  	if err != nil {
   512  		return "", err
   513  	}
   514  	return string(doc), nil
   515  }
   516  
   517  func (s *NetworkDNSSRV) Unmarshal(doc string) error {
   518  	return xml.Unmarshal([]byte(doc), s)
   519  }
   520  
   521  func (s *NetworkDNSSRV) Marshal() (string, error) {
   522  	doc, err := xml.MarshalIndent(s, "", "  ")
   523  	if err != nil {
   524  		return "", err
   525  	}
   526  	return string(doc), nil
   527  }
   528  
   529  func (s *NetworkDHCPRange) Unmarshal(doc string) error {
   530  	return xml.Unmarshal([]byte(doc), s)
   531  }
   532  
   533  func (s *NetworkDHCPRange) Marshal() (string, error) {
   534  	doc, err := xml.MarshalIndent(s, "", "  ")
   535  	if err != nil {
   536  		return "", err
   537  	}
   538  	return string(doc), nil
   539  }
   540  
   541  func (s *NetworkForwardInterface) Unmarshal(doc string) error {
   542  	return xml.Unmarshal([]byte(doc), s)
   543  }
   544  
   545  func (s *NetworkForwardInterface) Marshal() (string, error) {
   546  	doc, err := xml.MarshalIndent(s, "", "  ")
   547  	if err != nil {
   548  		return "", err
   549  	}
   550  	return string(doc), nil
   551  }
   552  
   553  func (s *Network) Unmarshal(doc string) error {
   554  	return xml.Unmarshal([]byte(doc), s)
   555  }
   556  
   557  func (s *Network) Marshal() (string, error) {
   558  	doc, err := xml.MarshalIndent(s, "", "  ")
   559  	if err != nil {
   560  		return "", err
   561  	}
   562  	return string(doc), nil
   563  }