github.com/zhaoxuat/libvirt-go-xml@v6.3.1-0.20200612053919-a025f1d30c41+incompatible/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  	Addresses []NetworkForwardNATAddress `xml:"address"`
    98  	Ports     []NetworkForwardNATPort    `xml:"port"`
    99  }
   100  
   101  type NetworkForward struct {
   102  	Mode       string                    `xml:"mode,attr,omitempty"`
   103  	Dev        string                    `xml:"dev,attr,omitempty"`
   104  	Managed    string                    `xml:"managed,attr,omitempty"`
   105  	Driver     *NetworkForwardDriver     `xml:"driver"`
   106  	PFs        []NetworkForwardPF        `xml:"pf"`
   107  	NAT        *NetworkForwardNAT        `xml:"nat"`
   108  	Interfaces []NetworkForwardInterface `xml:"interface"`
   109  	Addresses  []NetworkForwardAddress   `xml:"address"`
   110  }
   111  
   112  type NetworkForwardDriver struct {
   113  	Name string `xml:"name,attr"`
   114  }
   115  
   116  type NetworkForwardPF struct {
   117  	Dev string `xml:"dev,attr"`
   118  }
   119  
   120  type NetworkForwardAddress struct {
   121  	PCI *NetworkForwardAddressPCI `xml:"-"`
   122  }
   123  
   124  type NetworkForwardAddressPCI struct {
   125  	Domain   *uint `xml:"domain,attr"`
   126  	Bus      *uint `xml:"bus,attr"`
   127  	Slot     *uint `xml:"slot,attr"`
   128  	Function *uint `xml:"function,attr"`
   129  }
   130  
   131  type NetworkForwardInterface struct {
   132  	XMLName xml.Name `xml:"interface"`
   133  	Dev     string   `xml:"dev,attr,omitempty"`
   134  }
   135  
   136  type NetworkMAC struct {
   137  	Address string `xml:"address,attr,omitempty"`
   138  }
   139  
   140  type NetworkDHCPRange struct {
   141  	XMLName xml.Name          `xml:"range"`
   142  	Start   string            `xml:"start,attr,omitempty"`
   143  	End     string            `xml:"end,attr,omitempty"`
   144  	Lease   *NetworkDHCPLease `xml:"lease"`
   145  }
   146  
   147  type NetworkDHCPLease struct {
   148  	Expiry uint   `xml:"expiry,attr"`
   149  	Unit   string `xml:"unit,attr,omitempty"`
   150  }
   151  
   152  type NetworkDHCPHost struct {
   153  	XMLName xml.Name          `xml:"host"`
   154  	ID      string            `xml:"id,attr,omitempty"`
   155  	MAC     string            `xml:"mac,attr,omitempty"`
   156  	Name    string            `xml:"name,attr,omitempty"`
   157  	IP      string            `xml:"ip,attr,omitempty"`
   158  	Lease   *NetworkDHCPLease `xml:"lease"`
   159  }
   160  
   161  type NetworkBootp struct {
   162  	File   string `xml:"file,attr,omitempty"`
   163  	Server string `xml:"server,attr,omitempty"`
   164  }
   165  
   166  type NetworkDHCP struct {
   167  	Ranges []NetworkDHCPRange `xml:"range"`
   168  	Hosts  []NetworkDHCPHost  `xml:"host"`
   169  	Bootp  []NetworkBootp     `xml:"bootp"`
   170  }
   171  
   172  type NetworkIP struct {
   173  	Address  string       `xml:"address,attr,omitempty"`
   174  	Family   string       `xml:"family,attr,omitempty"`
   175  	Netmask  string       `xml:"netmask,attr,omitempty"`
   176  	Prefix   uint         `xml:"prefix,attr,omitempty"`
   177  	LocalPtr string       `xml:"localPtr,attr,omitempty"`
   178  	DHCP     *NetworkDHCP `xml:"dhcp"`
   179  	TFTP     *NetworkTFTP `xml:"tftp"`
   180  }
   181  
   182  type NetworkTFTP struct {
   183  	Root string `xml:"root,attr,omitempty"`
   184  }
   185  
   186  type NetworkRoute struct {
   187  	Family  string `xml:"family,attr,omitempty"`
   188  	Address string `xml:"address,attr,omitempty"`
   189  	Netmask string `xml:"netmask,attr,omitempty"`
   190  	Prefix  uint   `xml:"prefix,attr,omitempty"`
   191  	Gateway string `xml:"gateway,attr,omitempty"`
   192  	Metric  string `xml:"metric,attr,omitempty"`
   193  }
   194  
   195  type NetworkDNSForwarder struct {
   196  	Domain string `xml:"domain,attr,omitempty"`
   197  	Addr   string `xml:"addr,attr,omitempty"`
   198  }
   199  
   200  type NetworkDNSTXT struct {
   201  	XMLName xml.Name `xml:"txt"`
   202  	Name    string   `xml:"name,attr"`
   203  	Value   string   `xml:"value,attr"`
   204  }
   205  
   206  type NetworkDNSHostHostname struct {
   207  	Hostname string `xml:",chardata"`
   208  }
   209  
   210  type NetworkDNSHost struct {
   211  	XMLName   xml.Name                 `xml:"host"`
   212  	IP        string                   `xml:"ip,attr"`
   213  	Hostnames []NetworkDNSHostHostname `xml:"hostname"`
   214  }
   215  
   216  type NetworkDNSSRV struct {
   217  	XMLName  xml.Name `xml:"srv"`
   218  	Service  string   `xml:"service,attr,omitempty"`
   219  	Protocol string   `xml:"protocol,attr,omitempty"`
   220  	Target   string   `xml:"target,attr,omitempty"`
   221  	Port     uint     `xml:"port,attr,omitempty"`
   222  	Priority uint     `xml:"priority,attr,omitempty"`
   223  	Weight   uint     `xml:"weight,attr,omitempty"`
   224  	Domain   string   `xml:"domain,attr,omitempty"`
   225  }
   226  
   227  type NetworkDNS struct {
   228  	Enable            string                `xml:"enable,attr,omitempty"`
   229  	ForwardPlainNames string                `xml:"forwardPlainNames,attr,omitempty"`
   230  	Forwarders        []NetworkDNSForwarder `xml:"forwarder"`
   231  	TXTs              []NetworkDNSTXT       `xml:"txt"`
   232  	Host              []NetworkDNSHost      `xml:"host"`
   233  	SRVs              []NetworkDNSSRV       `xml:"srv"`
   234  }
   235  
   236  type NetworkMetadata struct {
   237  	XML string `xml:",innerxml"`
   238  }
   239  
   240  type NetworkMTU struct {
   241  	Size uint `xml:"size,attr"`
   242  }
   243  
   244  type Network struct {
   245  	XMLName             xml.Name            `xml:"network"`
   246  	IPv6                string              `xml:"ipv6,attr,omitempty"`
   247  	TrustGuestRxFilters string              `xml:"trustGuestRxFilters,attr,omitempty"`
   248  	Name                string              `xml:"name,omitempty"`
   249  	UUID                string              `xml:"uuid,omitempty"`
   250  	Metadata            *NetworkMetadata    `xml:"metadata"`
   251  	Forward             *NetworkForward     `xml:"forward"`
   252  	Bridge              *NetworkBridge      `xml:"bridge"`
   253  	MTU                 *NetworkMTU         `xml:"mtu"`
   254  	MAC                 *NetworkMAC         `xml:"mac"`
   255  	Domain              *NetworkDomain      `xml:"domain"`
   256  	DNS                 *NetworkDNS         `xml:"dns"`
   257  	VLAN                *NetworkVLAN        `xml:"vlan"`
   258  	Bandwidth           *NetworkBandwidth   `xml:"bandwidth"`
   259  	PortOptions         *NetworkPortOptions `xml:"port"`
   260  	IPs                 []NetworkIP         `xml:"ip"`
   261  	Routes              []NetworkRoute      `xml:"route"`
   262  	VirtualPort         *NetworkVirtualPort `xml:"virtualport"`
   263  	PortGroups          []NetworkPortGroup  `xml:"portgroup"`
   264  
   265  	DnsmasqOptions *NetworkDnsmasqOptions
   266  }
   267  
   268  type NetworkPortOptions struct {
   269  	Isolated string `xml:"isolated,attr,omitempty"`
   270  }
   271  
   272  type NetworkPortGroup struct {
   273  	XMLName             xml.Name            `xml:"portgroup"`
   274  	Name                string              `xml:"name,attr,omitempty"`
   275  	Default             string              `xml:"default,attr,omitempty"`
   276  	TrustGuestRxFilters string              `xml:"trustGuestRxFilters,attr,omitempty"`
   277  	VLAN                *NetworkVLAN        `xml:"vlan"`
   278  	VirtualPort         *NetworkVirtualPort `xml:"virtualport"`
   279  }
   280  
   281  type NetworkVLAN struct {
   282  	Trunk string           `xml:"trunk,attr,omitempty"`
   283  	Tags  []NetworkVLANTag `xml:"tag"`
   284  }
   285  
   286  type NetworkVLANTag struct {
   287  	ID         uint   `xml:"id,attr"`
   288  	NativeMode string `xml:"nativeMode,attr,omitempty"`
   289  }
   290  
   291  type NetworkBandwidthParams struct {
   292  	Average *uint `xml:"average,attr"`
   293  	Peak    *uint `xml:"peak,attr"`
   294  	Burst   *uint `xml:"burst,attr"`
   295  	Floor   *uint `xml:"floor,attr"`
   296  }
   297  
   298  type NetworkBandwidth struct {
   299  	ClassID  uint                    `xml:"classID,attr,omitempty"`
   300  	Inbound  *NetworkBandwidthParams `xml:"inbound"`
   301  	Outbound *NetworkBandwidthParams `xml:"outbound"`
   302  }
   303  
   304  type NetworkDnsmasqOptions struct {
   305  	XMLName xml.Name               `xml:"http://libvirt.org/schemas/network/dnsmasq/1.0 options"`
   306  	Option  []NetworkDnsmasqOption `xml:"option"`
   307  }
   308  
   309  type NetworkDnsmasqOption struct {
   310  	Value string `xml:"value,attr"`
   311  }
   312  
   313  func (a *NetworkVirtualPortParams) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   314  	start.Name.Local = "parameters"
   315  	if a.Any != nil {
   316  		return e.EncodeElement(a.Any, start)
   317  	} else if a.VEPA8021QBG != nil {
   318  		return e.EncodeElement(a.VEPA8021QBG, start)
   319  	} else if a.VNTag8011QBH != nil {
   320  		return e.EncodeElement(a.VNTag8011QBH, start)
   321  	} else if a.OpenVSwitch != nil {
   322  		return e.EncodeElement(a.OpenVSwitch, start)
   323  	} else if a.MidoNet != nil {
   324  		return e.EncodeElement(a.MidoNet, start)
   325  	}
   326  	return nil
   327  }
   328  
   329  func (a *NetworkVirtualPortParams) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   330  	if a.Any != nil {
   331  		return d.DecodeElement(a.Any, &start)
   332  	} else if a.VEPA8021QBG != nil {
   333  		return d.DecodeElement(a.VEPA8021QBG, &start)
   334  	} else if a.VNTag8011QBH != nil {
   335  		return d.DecodeElement(a.VNTag8011QBH, &start)
   336  	} else if a.OpenVSwitch != nil {
   337  		return d.DecodeElement(a.OpenVSwitch, &start)
   338  	} else if a.MidoNet != nil {
   339  		return d.DecodeElement(a.MidoNet, &start)
   340  	}
   341  	return nil
   342  }
   343  
   344  type networkVirtualPort NetworkVirtualPort
   345  
   346  func (a *NetworkVirtualPort) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   347  	start.Name.Local = "virtualport"
   348  	if a.Params != nil {
   349  		if a.Params.Any != nil {
   350  			/* no type attr wanted */
   351  		} else if a.Params.VEPA8021QBG != nil {
   352  			start.Attr = append(start.Attr, xml.Attr{
   353  				xml.Name{Local: "type"}, "802.1Qbg",
   354  			})
   355  		} else if a.Params.VNTag8011QBH != nil {
   356  			start.Attr = append(start.Attr, xml.Attr{
   357  				xml.Name{Local: "type"}, "802.1Qbh",
   358  			})
   359  		} else if a.Params.OpenVSwitch != nil {
   360  			start.Attr = append(start.Attr, xml.Attr{
   361  				xml.Name{Local: "type"}, "openvswitch",
   362  			})
   363  		} else if a.Params.MidoNet != nil {
   364  			start.Attr = append(start.Attr, xml.Attr{
   365  				xml.Name{Local: "type"}, "midonet",
   366  			})
   367  		}
   368  	}
   369  	vp := networkVirtualPort(*a)
   370  	return e.EncodeElement(&vp, start)
   371  }
   372  
   373  func (a *NetworkVirtualPort) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   374  	typ, ok := getAttr(start.Attr, "type")
   375  	a.Params = &NetworkVirtualPortParams{}
   376  	if !ok {
   377  		var any NetworkVirtualPortParamsAny
   378  		a.Params.Any = &any
   379  	} else if typ == "802.1Qbg" {
   380  		var vepa NetworkVirtualPortParamsVEPA8021QBG
   381  		a.Params.VEPA8021QBG = &vepa
   382  	} else if typ == "802.1Qbh" {
   383  		var vntag NetworkVirtualPortParamsVNTag8021QBH
   384  		a.Params.VNTag8011QBH = &vntag
   385  	} else if typ == "openvswitch" {
   386  		var ovs NetworkVirtualPortParamsOpenVSwitch
   387  		a.Params.OpenVSwitch = &ovs
   388  	} else if typ == "midonet" {
   389  		var mido NetworkVirtualPortParamsMidoNet
   390  		a.Params.MidoNet = &mido
   391  	}
   392  
   393  	vp := networkVirtualPort(*a)
   394  	err := d.DecodeElement(&vp, &start)
   395  	if err != nil {
   396  		return err
   397  	}
   398  	*a = NetworkVirtualPort(vp)
   399  	return nil
   400  }
   401  
   402  func (a *NetworkForwardAddressPCI) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   403  	marshalUintAttr(&start, "domain", a.Domain, "0x%04x")
   404  	marshalUintAttr(&start, "bus", a.Bus, "0x%02x")
   405  	marshalUintAttr(&start, "slot", a.Slot, "0x%02x")
   406  	marshalUintAttr(&start, "function", a.Function, "0x%x")
   407  	e.EncodeToken(start)
   408  	e.EncodeToken(start.End())
   409  	return nil
   410  }
   411  
   412  func (a *NetworkForwardAddressPCI) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   413  	for _, attr := range start.Attr {
   414  		if attr.Name.Local == "domain" {
   415  			if err := unmarshalUintAttr(attr.Value, &a.Domain, 0); err != nil {
   416  				return err
   417  			}
   418  		} else if attr.Name.Local == "bus" {
   419  			if err := unmarshalUintAttr(attr.Value, &a.Bus, 0); err != nil {
   420  				return err
   421  			}
   422  		} else if attr.Name.Local == "slot" {
   423  			if err := unmarshalUintAttr(attr.Value, &a.Slot, 0); err != nil {
   424  				return err
   425  			}
   426  		} else if attr.Name.Local == "function" {
   427  			if err := unmarshalUintAttr(attr.Value, &a.Function, 0); err != nil {
   428  				return err
   429  			}
   430  		}
   431  	}
   432  	d.Skip()
   433  	return nil
   434  }
   435  
   436  func (a *NetworkForwardAddress) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   437  	if a.PCI != nil {
   438  		start.Attr = append(start.Attr, xml.Attr{
   439  			xml.Name{Local: "type"}, "pci",
   440  		})
   441  		return e.EncodeElement(a.PCI, start)
   442  	} else {
   443  		return nil
   444  	}
   445  }
   446  
   447  func (a *NetworkForwardAddress) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   448  	var typ string
   449  	for _, attr := range start.Attr {
   450  		if attr.Name.Local == "type" {
   451  			typ = attr.Value
   452  			break
   453  		}
   454  	}
   455  	if typ == "" {
   456  		d.Skip()
   457  		return nil
   458  	}
   459  
   460  	if typ == "pci" {
   461  		a.PCI = &NetworkForwardAddressPCI{}
   462  		return d.DecodeElement(a.PCI, &start)
   463  	}
   464  
   465  	return nil
   466  }
   467  
   468  func (s *NetworkDHCPHost) Unmarshal(doc string) error {
   469  	return xml.Unmarshal([]byte(doc), s)
   470  }
   471  
   472  func (s *NetworkDHCPHost) Marshal() (string, error) {
   473  	doc, err := xml.MarshalIndent(s, "", "  ")
   474  	if err != nil {
   475  		return "", err
   476  	}
   477  	return string(doc), nil
   478  }
   479  
   480  func (s *NetworkDNSHost) Unmarshal(doc string) error {
   481  	return xml.Unmarshal([]byte(doc), s)
   482  }
   483  
   484  func (s *NetworkDNSHost) Marshal() (string, error) {
   485  	doc, err := xml.MarshalIndent(s, "", "  ")
   486  	if err != nil {
   487  		return "", err
   488  	}
   489  	return string(doc), nil
   490  }
   491  
   492  func (s *NetworkPortGroup) Unmarshal(doc string) error {
   493  	return xml.Unmarshal([]byte(doc), s)
   494  }
   495  
   496  func (s *NetworkPortGroup) Marshal() (string, error) {
   497  	doc, err := xml.MarshalIndent(s, "", "  ")
   498  	if err != nil {
   499  		return "", err
   500  	}
   501  	return string(doc), nil
   502  }
   503  
   504  func (s *NetworkDNSTXT) Unmarshal(doc string) error {
   505  	return xml.Unmarshal([]byte(doc), s)
   506  }
   507  
   508  func (s *NetworkDNSTXT) Marshal() (string, error) {
   509  	doc, err := xml.MarshalIndent(s, "", "  ")
   510  	if err != nil {
   511  		return "", err
   512  	}
   513  	return string(doc), nil
   514  }
   515  
   516  func (s *NetworkDNSSRV) Unmarshal(doc string) error {
   517  	return xml.Unmarshal([]byte(doc), s)
   518  }
   519  
   520  func (s *NetworkDNSSRV) Marshal() (string, error) {
   521  	doc, err := xml.MarshalIndent(s, "", "  ")
   522  	if err != nil {
   523  		return "", err
   524  	}
   525  	return string(doc), nil
   526  }
   527  
   528  func (s *NetworkDHCPRange) Unmarshal(doc string) error {
   529  	return xml.Unmarshal([]byte(doc), s)
   530  }
   531  
   532  func (s *NetworkDHCPRange) Marshal() (string, error) {
   533  	doc, err := xml.MarshalIndent(s, "", "  ")
   534  	if err != nil {
   535  		return "", err
   536  	}
   537  	return string(doc), nil
   538  }
   539  
   540  func (s *NetworkForwardInterface) Unmarshal(doc string) error {
   541  	return xml.Unmarshal([]byte(doc), s)
   542  }
   543  
   544  func (s *NetworkForwardInterface) Marshal() (string, error) {
   545  	doc, err := xml.MarshalIndent(s, "", "  ")
   546  	if err != nil {
   547  		return "", err
   548  	}
   549  	return string(doc), nil
   550  }
   551  
   552  func (s *Network) Unmarshal(doc string) error {
   553  	return xml.Unmarshal([]byte(doc), s)
   554  }
   555  
   556  func (s *Network) Marshal() (string, error) {
   557  	doc, err := xml.MarshalIndent(s, "", "  ")
   558  	if err != nil {
   559  		return "", err
   560  	}
   561  	return string(doc), nil
   562  }