libvirt.org/go/libvirtxml@v1.10003.0/network.go (about)

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