...

Source file src/github.com/openshift/api/imageregistry/v1/types.go

Documentation: github.com/openshift/api/imageregistry/v1

     1  package v1
     2  
     3  import (
     4  	corev1 "k8s.io/api/core/v1"
     5  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     6  
     7  	operatorv1 "github.com/openshift/api/operator/v1"
     8  )
     9  
    10  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
    11  
    12  // ConfigList is a slice of Config objects.
    13  //
    14  // Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
    15  // +openshift:compatibility-gen:level=1
    16  type ConfigList struct {
    17  	metav1.TypeMeta `json:",inline"`
    18  
    19  	// metadata is the standard list's metadata.
    20  	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
    21  	metav1.ListMeta `json:"metadata"`
    22  	Items           []Config `json:"items"`
    23  }
    24  
    25  const (
    26  	// StorageManagementStateManaged indicates the operator is managing the underlying storage.
    27  	StorageManagementStateManaged = "Managed"
    28  	// StorageManagementStateUnmanaged indicates the operator is not managing the underlying
    29  	// storage.
    30  	StorageManagementStateUnmanaged = "Unmanaged"
    31  )
    32  
    33  // +genclient
    34  // +genclient:nonNamespaced
    35  // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
    36  
    37  // Config is the configuration object for a registry instance managed by
    38  // the registry operator
    39  //
    40  // Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
    41  // +openshift:compatibility-gen:level=1
    42  type Config struct {
    43  	metav1.TypeMeta `json:",inline"`
    44  
    45  	// metadata is the standard object's metadata.
    46  	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
    47  	metav1.ObjectMeta `json:"metadata"`
    48  
    49  	Spec ImageRegistrySpec `json:"spec"`
    50  	// +optional
    51  	Status ImageRegistryStatus `json:"status,omitempty"`
    52  }
    53  
    54  // ImageRegistrySpec defines the specs for the running registry.
    55  type ImageRegistrySpec struct {
    56  	// operatorSpec allows operator specific configuration to be made.
    57  	operatorv1.OperatorSpec `json:",inline"`
    58  	// httpSecret is the value needed by the registry to secure uploads, generated by default.
    59  	// +optional
    60  	HTTPSecret string `json:"httpSecret,omitempty"`
    61  	// proxy defines the proxy to be used when calling master api, upstream
    62  	// registries, etc.
    63  	// +optional
    64  	Proxy ImageRegistryConfigProxy `json:"proxy,omitempty"`
    65  	// storage details for configuring registry storage, e.g. S3 bucket
    66  	// coordinates.
    67  	// +optional
    68  	Storage ImageRegistryConfigStorage `json:"storage,omitempty"`
    69  	// readOnly indicates whether the registry instance should reject attempts
    70  	// to push new images or delete existing ones.
    71  	// +optional
    72  	ReadOnly bool `json:"readOnly,omitempty"`
    73  	// disableRedirect controls whether to route all data through the Registry,
    74  	// rather than redirecting to the backend.
    75  	// +optional
    76  	DisableRedirect bool `json:"disableRedirect,omitempty"`
    77  	// requests controls how many parallel requests a given registry instance
    78  	// will handle before queuing additional requests.
    79  	// +optional
    80  	Requests ImageRegistryConfigRequests `json:"requests,omitempty"`
    81  	// defaultRoute indicates whether an external facing route for the registry
    82  	// should be created using the default generated hostname.
    83  	// +optional
    84  	DefaultRoute bool `json:"defaultRoute,omitempty"`
    85  	// routes defines additional external facing routes which should be
    86  	// created for the registry.
    87  	// +optional
    88  	Routes []ImageRegistryConfigRoute `json:"routes,omitempty"`
    89  	// replicas determines the number of registry instances to run.
    90  	Replicas int32 `json:"replicas"`
    91  	// logging is deprecated, use logLevel instead.
    92  	// +optional
    93  	Logging int64 `json:"logging,omitempty"`
    94  	// resources defines the resource requests+limits for the registry pod.
    95  	// +optional
    96  	Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
    97  	// nodeSelector defines the node selection constraints for the registry
    98  	// pod.
    99  	// +optional
   100  	NodeSelector map[string]string `json:"nodeSelector,omitempty"`
   101  	// tolerations defines the tolerations for the registry pod.
   102  	// +optional
   103  	Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
   104  	// rolloutStrategy defines rollout strategy for the image registry
   105  	// deployment.
   106  	// +optional
   107  	// +kubebuilder:validation:Pattern=`^(RollingUpdate|Recreate)$`
   108  	RolloutStrategy string `json:"rolloutStrategy,omitempty"`
   109  	// affinity is a group of node affinity scheduling rules for the image registry pod(s).
   110  	// +optional
   111  	Affinity *corev1.Affinity `json:"affinity,omitempty"`
   112  	// topologySpreadConstraints specify how to spread matching pods among the given topology.
   113  	// +optional
   114  	TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty"`
   115  }
   116  
   117  // ImageRegistryStatus reports image registry operational status.
   118  type ImageRegistryStatus struct {
   119  	operatorv1.OperatorStatus `json:",inline"`
   120  
   121  	// storageManaged is deprecated, please refer to Storage.managementState
   122  	StorageManaged bool `json:"storageManaged"`
   123  	// storage indicates the current applied storage configuration of the
   124  	// registry.
   125  	Storage ImageRegistryConfigStorage `json:"storage"`
   126  }
   127  
   128  // ImageRegistryConfigProxy defines proxy configuration to be used by registry.
   129  type ImageRegistryConfigProxy struct {
   130  	// http defines the proxy to be used by the image registry when
   131  	// accessing HTTP endpoints.
   132  	// +optional
   133  	HTTP string `json:"http,omitempty"`
   134  	// https defines the proxy to be used by the image registry when
   135  	// accessing HTTPS endpoints.
   136  	// +optional
   137  	HTTPS string `json:"https,omitempty"`
   138  	// noProxy defines a comma-separated list of host names that shouldn't
   139  	// go through any proxy.
   140  	// +optional
   141  	NoProxy string `json:"noProxy,omitempty"`
   142  }
   143  
   144  // ImageRegistryConfigStorageS3CloudFront holds the configuration
   145  // to use Amazon Cloudfront as the storage middleware in a registry.
   146  // https://docs.docker.com/registry/configuration/#cloudfront
   147  type ImageRegistryConfigStorageS3CloudFront struct {
   148  	// baseURL contains the SCHEME://HOST[/PATH] at which Cloudfront is served.
   149  	BaseURL string `json:"baseURL"`
   150  	// privateKey points to secret containing the private key, provided by AWS.
   151  	PrivateKey corev1.SecretKeySelector `json:"privateKey"`
   152  	// keypairID is key pair ID provided by AWS.
   153  	KeypairID string `json:"keypairID"`
   154  	// duration is the duration of the Cloudfront session.
   155  	// +optional
   156  	// +kubebuilder:validation:Format=duration
   157  	Duration metav1.Duration `json:"duration,omitempty"`
   158  }
   159  
   160  // ImageRegistryConfigStorageEmptyDir is an place holder to be used when
   161  // when registry is leveraging ephemeral storage.
   162  type ImageRegistryConfigStorageEmptyDir struct {
   163  }
   164  
   165  // S3TrustedCASource references a config map with a CA certificate bundle in
   166  // the "openshift-config" namespace. The key for the bundle in the
   167  // config map is "ca-bundle.crt".
   168  type S3TrustedCASource struct {
   169  	// name is the metadata.name of the referenced config map.
   170  	// This field must adhere to standard config map naming restrictions.
   171  	// The name must consist solely of alphanumeric characters, hyphens (-)
   172  	// and periods (.). It has a maximum length of 253 characters.
   173  	// If this field is not specified or is empty string, the default trust
   174  	// bundle will be used.
   175  	// +kubebuilder:validation:MaxLength=253
   176  	// +kubebuilder:validation:Pattern=`^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
   177  	// +optional
   178  	Name string `json:"name"`
   179  }
   180  
   181  // ImageRegistryConfigStorageS3 holds the information to configure
   182  // the registry to use the AWS S3 service for backend storage
   183  // https://docs.docker.com/registry/storage-drivers/s3/
   184  type ImageRegistryConfigStorageS3 struct {
   185  	// bucket is the bucket name in which you want to store the registry's
   186  	// data.
   187  	// Optional, will be generated if not provided.
   188  	// +optional
   189  	Bucket string `json:"bucket,omitempty"`
   190  	// region is the AWS region in which your bucket exists.
   191  	// Optional, will be set based on the installed AWS Region.
   192  	// +optional
   193  	Region string `json:"region,omitempty"`
   194  	// regionEndpoint is the endpoint for S3 compatible storage services.
   195  	// It should be a valid URL with scheme, e.g. https://s3.example.com.
   196  	// Optional, defaults based on the Region that is provided.
   197  	// +optional
   198  	RegionEndpoint string `json:"regionEndpoint,omitempty"`
   199  	// encrypt specifies whether the registry stores the image in encrypted
   200  	// format or not.
   201  	// Optional, defaults to false.
   202  	// +optional
   203  	Encrypt bool `json:"encrypt,omitempty"`
   204  	// keyID is the KMS key ID to use for encryption.
   205  	// Optional, Encrypt must be true, or this parameter is ignored.
   206  	// +optional
   207  	KeyID string `json:"keyID,omitempty"`
   208  	// cloudFront configures Amazon Cloudfront as the storage middleware in a
   209  	// registry.
   210  	// +optional
   211  	CloudFront *ImageRegistryConfigStorageS3CloudFront `json:"cloudFront,omitempty"`
   212  	// virtualHostedStyle enables using S3 virtual hosted style bucket paths with
   213  	// a custom RegionEndpoint
   214  	// Optional, defaults to false.
   215  	// +optional
   216  	VirtualHostedStyle bool `json:"virtualHostedStyle"`
   217  	// trustedCA is a reference to a config map containing a CA bundle. The
   218  	// image registry and its operator use certificates from this bundle to
   219  	// verify S3 server certificates.
   220  	//
   221  	// The namespace for the config map referenced by trustedCA is
   222  	// "openshift-config". The key for the bundle in the config map is
   223  	// "ca-bundle.crt".
   224  	// +optional
   225  	TrustedCA S3TrustedCASource `json:"trustedCA"`
   226  }
   227  
   228  // ImageRegistryConfigStorageGCS holds GCS configuration.
   229  type ImageRegistryConfigStorageGCS struct {
   230  	// bucket is the bucket name in which you want to store the registry's
   231  	// data.
   232  	// Optional, will be generated if not provided.
   233  	// +optional
   234  	Bucket string `json:"bucket,omitempty"`
   235  	// region is the GCS location in which your bucket exists.
   236  	// Optional, will be set based on the installed GCS Region.
   237  	// +optional
   238  	Region string `json:"region,omitempty"`
   239  	// projectID is the Project ID of the GCP project that this bucket should
   240  	// be associated with.
   241  	// +optional
   242  	ProjectID string `json:"projectID,omitempty"`
   243  	// keyID is the KMS key ID to use for encryption.
   244  	// Optional, buckets are encrypted by default on GCP.
   245  	// This allows for the use of a custom encryption key.
   246  	// +optional
   247  	KeyID string `json:"keyID,omitempty"`
   248  }
   249  
   250  // ImageRegistryConfigStorageSwift holds the information to configure
   251  // the registry to use the OpenStack Swift service for backend storage
   252  // https://docs.docker.com/registry/storage-drivers/swift/
   253  type ImageRegistryConfigStorageSwift struct {
   254  	// authURL defines the URL for obtaining an authentication token.
   255  	// +optional
   256  	AuthURL string `json:"authURL,omitempty"`
   257  	// authVersion specifies the OpenStack Auth's version.
   258  	// +optional
   259  	AuthVersion string `json:"authVersion,omitempty"`
   260  	// container defines the name of Swift container where to store the
   261  	// registry's data.
   262  	// +optional
   263  	Container string `json:"container,omitempty"`
   264  	// domain specifies Openstack's domain name for Identity v3 API.
   265  	// +optional
   266  	Domain string `json:"domain,omitempty"`
   267  	// domainID specifies Openstack's domain id for Identity v3 API.
   268  	// +optional
   269  	DomainID string `json:"domainID,omitempty"`
   270  	// tenant defines Openstack tenant name to be used by registry.
   271  	// +optional
   272  	Tenant string `json:"tenant,omitempty"`
   273  	// tenant defines Openstack tenant id to be used by registry.
   274  	// +optional
   275  	TenantID string `json:"tenantID,omitempty"`
   276  	// regionName defines Openstack's region in which container exists.
   277  	// +optional
   278  	RegionName string `json:"regionName,omitempty"`
   279  }
   280  
   281  // ImageRegistryConfigStoragePVC holds Persistent Volume Claims data to
   282  // be used by the registry.
   283  type ImageRegistryConfigStoragePVC struct {
   284  	// claim defines the Persisent Volume Claim's name to be used.
   285  	// +optional
   286  	Claim string `json:"claim,omitempty"`
   287  }
   288  
   289  // ImageRegistryConfigStorageAzure holds the information to configure
   290  // the registry to use Azure Blob Storage for backend storage.
   291  type ImageRegistryConfigStorageAzure struct {
   292  	// accountName defines the account to be used by the registry.
   293  	// +optional
   294  	AccountName string `json:"accountName,omitempty"`
   295  	// container defines Azure's container to be used by registry.
   296  	// +optional
   297  	// +kubebuilder:validation:MaxLength=63
   298  	// +kubebuilder:validation:MinLength=3
   299  	// +kubebuilder:validation:Pattern=`^[0-9a-z]+(-[0-9a-z]+)*$`
   300  	Container string `json:"container,omitempty"`
   301  	// cloudName is the name of the Azure cloud environment to be used by the
   302  	// registry. If empty, the operator will set it based on the infrastructure
   303  	// object.
   304  	// +optional
   305  	CloudName string `json:"cloudName,omitempty"`
   306  }
   307  
   308  // ImageRegistryConfigStorageIBMCOS holds the information to configure
   309  // the registry to use IBM Cloud Object Storage for backend storage.
   310  type ImageRegistryConfigStorageIBMCOS struct {
   311  	// bucket is the bucket name in which you want to store the registry's
   312  	// data.
   313  	// Optional, will be generated if not provided.
   314  	// +optional
   315  	Bucket string `json:"bucket,omitempty"`
   316  	// location is the IBM Cloud location in which your bucket exists.
   317  	// Optional, will be set based on the installed IBM Cloud location.
   318  	// +optional
   319  	Location string `json:"location,omitempty"`
   320  	// resourceGroupName is the name of the IBM Cloud resource group that this
   321  	// bucket and its service instance is associated with.
   322  	// Optional, will be set based on the installed IBM Cloud resource group.
   323  	// +optional
   324  	ResourceGroupName string `json:"resourceGroupName,omitempty"`
   325  	// resourceKeyCRN is the CRN of the IBM Cloud resource key that is created
   326  	// for the service instance. Commonly referred as a service credential and
   327  	// must contain HMAC type credentials.
   328  	// Optional, will be computed if not provided.
   329  	// +optional
   330  	// +kubebuilder:validation:Pattern=`^crn:.+:.+:.+:cloud-object-storage:.+:.+:.+:resource-key:.+$`
   331  	ResourceKeyCRN string `json:"resourceKeyCRN,omitempty"`
   332  	// serviceInstanceCRN is the CRN of the IBM Cloud Object Storage service
   333  	// instance that this bucket is associated with.
   334  	// Optional, will be computed if not provided.
   335  	// +optional
   336  	// +kubebuilder:validation:Pattern=`^crn:.+:.+:.+:cloud-object-storage:.+:.+:.+::$`
   337  	ServiceInstanceCRN string `json:"serviceInstanceCRN,omitempty"`
   338  }
   339  
   340  // EndpointAccessibility defines the Alibaba VPC endpoint for storage
   341  type EndpointAccessibility string
   342  
   343  // AlibabaEncryptionMethod defines an enumerable type for the encryption mode
   344  type AlibabaEncryptionMethod string
   345  
   346  const (
   347  	// InternalEndpoint sets the VPC endpoint to internal
   348  	InternalEndpoint EndpointAccessibility = "Internal"
   349  	// PublicEndpoint sets the VPC endpoint to public
   350  	PublicEndpoint EndpointAccessibility = "Public"
   351  
   352  	// AES256 is an AlibabaEncryptionMethod. This means AES256 encryption
   353  	AES256 AlibabaEncryptionMethod = "AES256"
   354  	// KMS is an AlibabaEncryptionMethod. This means KMS encryption
   355  	KMS AlibabaEncryptionMethod = "KMS"
   356  )
   357  
   358  // EncryptionAlibaba this a union type in kube parlance.  Depending on the value for the AlibabaEncryptionMethod,
   359  // different pointers may be used
   360  type EncryptionAlibaba struct {
   361  	// Method defines the different encrytion modes available
   362  	// Empty value means no opinion and the platform chooses the a default, which is subject to change over time.
   363  	// Currently the default is `AES256`.
   364  	// +kubebuilder:validation:Enum="KMS";"AES256"
   365  	// +kubebuilder:default="AES256"
   366  	// +optional
   367  	Method AlibabaEncryptionMethod `json:"method"`
   368  
   369  	// KMS (key management service) is an encryption type that holds the struct for KMS KeyID
   370  	// +optional
   371  	KMS *KMSEncryptionAlibaba `json:"kms,omitempty"`
   372  }
   373  
   374  type KMSEncryptionAlibaba struct {
   375  	// KeyID holds the KMS encryption key ID
   376  	// +kubebuilder:validation:Required
   377  	// +kubebuilder:validation:MinLength=1
   378  	KeyID string `json:"keyID"`
   379  }
   380  
   381  // ImageRegistryConfigStorageAlibabaOSS holds Alibaba Cloud OSS configuration.
   382  // Configures the registry to use Alibaba Cloud Object Storage Service for backend storage.
   383  // More about oss, you can look at the [official documentation](https://www.alibabacloud.com/help/product/31815.htm)
   384  type ImageRegistryConfigStorageAlibabaOSS struct {
   385  	// Bucket is the bucket name in which you want to store the registry's data.
   386  	// About Bucket naming, more details you can look at the [official documentation](https://www.alibabacloud.com/help/doc-detail/257087.htm)
   387  	// Empty value means no opinion and the platform chooses the a default, which is subject to change over time.
   388  	// Currently the default will be autogenerated in the form of <clusterid>-image-registry-<region>-<random string 27 chars>
   389  	// +kubebuilder:validation:MaxLength=63
   390  	// +kubebuilder:validation:MinLength=3
   391  	// +kubebuilder:validation:Pattern=`^[0-9a-z]+(-[0-9a-z]+)*$`
   392  	// +optional
   393  	Bucket string `json:"bucket,omitempty"`
   394  	// Region is the Alibaba Cloud Region in which your bucket exists.
   395  	// For a list of regions, you can look at the [official documentation](https://www.alibabacloud.com/help/doc-detail/31837.html).
   396  	// Empty value means no opinion and the platform chooses the a default, which is subject to change over time.
   397  	// Currently the default will be based on the installed Alibaba Cloud Region.
   398  	// +optional
   399  	Region string `json:"region,omitempty"`
   400  	// EndpointAccessibility specifies whether the registry use the OSS VPC internal endpoint
   401  	// Empty value means no opinion and the platform chooses the a default, which is subject to change over time.
   402  	// Currently the default is `Internal`.
   403  	// +kubebuilder:validation:Enum="Internal";"Public";""
   404  	// +kubebuilder:default="Internal"
   405  	// +optional
   406  	EndpointAccessibility EndpointAccessibility `json:"endpointAccessibility,omitempty"`
   407  	// Encryption specifies whether you would like your data encrypted on the server side.
   408  	// More details, you can look cat the [official documentation](https://www.alibabacloud.com/help/doc-detail/117914.htm)
   409  	// +optional
   410  	Encryption *EncryptionAlibaba `json:"encryption,omitempty"`
   411  }
   412  
   413  // ImageRegistryConfigStorage describes how the storage should be configured
   414  // for the image registry.
   415  type ImageRegistryConfigStorage struct {
   416  	// emptyDir represents ephemeral storage on the pod's host node.
   417  	// WARNING: this storage cannot be used with more than 1 replica and
   418  	// is not suitable for production use. When the pod is removed from a
   419  	// node for any reason, the data in the emptyDir is deleted forever.
   420  	// +optional
   421  	EmptyDir *ImageRegistryConfigStorageEmptyDir `json:"emptyDir,omitempty"`
   422  	// s3 represents configuration that uses Amazon Simple Storage Service.
   423  	// +optional
   424  	S3 *ImageRegistryConfigStorageS3 `json:"s3,omitempty"`
   425  	// gcs represents configuration that uses Google Cloud Storage.
   426  	// +optional
   427  	GCS *ImageRegistryConfigStorageGCS `json:"gcs,omitempty"`
   428  	// swift represents configuration that uses OpenStack Object Storage.
   429  	// +optional
   430  	Swift *ImageRegistryConfigStorageSwift `json:"swift,omitempty"`
   431  	// pvc represents configuration that uses a PersistentVolumeClaim.
   432  	// +optional
   433  	PVC *ImageRegistryConfigStoragePVC `json:"pvc,omitempty"`
   434  	// azure represents configuration that uses Azure Blob Storage.
   435  	// +optional
   436  	Azure *ImageRegistryConfigStorageAzure `json:"azure,omitempty"`
   437  	// ibmcos represents configuration that uses IBM Cloud Object Storage.
   438  	// +optional
   439  	IBMCOS *ImageRegistryConfigStorageIBMCOS `json:"ibmcos,omitempty"`
   440  	// Oss represents configuration that uses Alibaba Cloud Object Storage Service.
   441  	// +optional
   442  	OSS *ImageRegistryConfigStorageAlibabaOSS `json:"oss,omitempty"`
   443  	// managementState indicates if the operator manages the underlying
   444  	// storage unit. If Managed the operator will remove the storage when
   445  	// this operator gets Removed.
   446  	// +optional
   447  	// +kubebuilder:validation:Pattern=`^(Managed|Unmanaged)$`
   448  	ManagementState string `json:"managementState,omitempty"`
   449  }
   450  
   451  // ImageRegistryConfigRequests defines registry limits on requests read and write.
   452  type ImageRegistryConfigRequests struct {
   453  	// read defines limits for image registry's reads.
   454  	// +optional
   455  	Read ImageRegistryConfigRequestsLimits `json:"read,omitempty"`
   456  	// write defines limits for image registry's writes.
   457  	// +optional
   458  	Write ImageRegistryConfigRequestsLimits `json:"write,omitempty"`
   459  }
   460  
   461  // ImageRegistryConfigRequestsLimits holds configuration on the max, enqueued
   462  // and waiting registry's API requests.
   463  type ImageRegistryConfigRequestsLimits struct {
   464  	// maxRunning sets the maximum in flight api requests to the registry.
   465  	// +optional
   466  	MaxRunning int `json:"maxRunning,omitempty"`
   467  	// maxInQueue sets the maximum queued api requests to the registry.
   468  	// +optional
   469  	MaxInQueue int `json:"maxInQueue,omitempty"`
   470  	// maxWaitInQueue sets the maximum time a request can wait in the queue
   471  	// before being rejected.
   472  	// +optional
   473  	// +kubebuilder:validation:Format=duration
   474  	MaxWaitInQueue metav1.Duration `json:"maxWaitInQueue,omitempty"`
   475  }
   476  
   477  // ImageRegistryConfigRoute holds information on external route access to image
   478  // registry.
   479  type ImageRegistryConfigRoute struct {
   480  	// name of the route to be created.
   481  	Name string `json:"name"`
   482  	// hostname for the route.
   483  	// +optional
   484  	Hostname string `json:"hostname,omitempty"`
   485  	// secretName points to secret containing the certificates to be used
   486  	// by the route.
   487  	// +optional
   488  	SecretName string `json:"secretName,omitempty"`
   489  }
   490  

View as plain text