dotnet-operator-sdk icon indicating copy to clipboard operation
dotnet-operator-sdk copied to clipboard

CRD generation fails for nested V1ObjectMeta

Open basilfx opened this issue 4 years ago • 12 comments

Describe the bug The CRD for an entity that uses a V1PodTemplateSpec does not allow any metadata fields to be set on that property.

To Reproduce Given the following custom entity:

using k8s.Models;
using KubeOps.Operator.Entities;
using KubeOps.Operator.Entities.Annotations;

namespace MyNamespace
{
    /// <summary>
    /// MyEntity specification.
    /// </summary>
    public class V1Alpha1MyEntitySpec
    {
        /// <summary>
        /// Gets or sets the pod template.
        /// </summary>
        [Required]
        public V1PodTemplateSpec Template { get; set; }
    }

    /// <summary>
    /// MyEntity status.
    /// </summary>
    public class V1Alpha1MyEntityStatus
    {

    }

    /// <summary>
    /// Definition of a MyEntity entity. This entity contains a specification of MyEntity instance.
    /// </summary>
    [KubernetesEntity(Kind = "MyEntity", Group = "my.group.com", ApiVersion = "v1alpha1")]
    public class V1Alpha1MyEntity : CustomKubernetesEntity<V1Alpha1MyEntitySpec, V1Alpha1MyEntityStatus>
    {

    }
}

It generates this CRD:

...
template:
  description: Gets or sets the pod template.
  properties:
    metadata:
      type: object // Here I would expect properties to be defined.
    spec:
      properties:
        activeDeadlineSeconds:
          format: int64
          nullable: true
          type: integer
      ...

If I would modify and persist an instance of the above entity, like below, it will not persists the labels or any other properties.

var entity = new V1Alpha1MyEntity();
entity.Spec.Template.Metadata.Labels["foo"] = "bar";

...

Expected behavior A valid CRD that accepts metadata.

Additional context When I modify the CRD to include x-kubernetes-preserve-unknown-fields: true, it works.

I believe it has to do with this part of the CRD generation, that may not hold for nested V1ObjectMeta's

basilfx avatar Jun 18 '21 11:06 basilfx

Could you try with the "embedded resource" attribute? There is an attribute, that should be used if sub-resources are linked in properties (like deployments or other kubernetes elements) https://buehler.github.io/dotnet-operator-sdk/kube-ops/KubeOps.Operator.Entities.Annotations.EmbeddedResourceAttribute.html

public class V1Alpha1MyEntitySpec
    {
        /// <summary>
        /// Gets or sets the pod template.
        /// </summary>
        [Required]
        [EmbeddedResource]
        public V1PodTemplateSpec Template { get; set; }
    }

This should fix your error and is the intended way of using sub resources

buehler avatar Jun 20 '21 18:06 buehler

That seems to do the trick, thanks!

basilfx avatar Jun 29 '21 06:06 basilfx

Reopening this, because it doesn't seem to really 'solve' the issue.

When I add [EmbeddedResource], I now also have to specify apiVersion and kind properties. These are not defined for V1PodTemplateSpec (which is actually part of a V1Deployment).

Note that in my CRD example above, the property activeDeadlineSeconds is part of the V1PodTemplateSpec, and the CRD for that part is generated correctly. It's everything under metadata that is not.

basilfx avatar Jun 29 '21 08:06 basilfx

I'm currently in an exam phase in my studies, as soon as this is over, I'm happy to analyze this matter.

buehler avatar Jul 02 '21 07:07 buehler

Hey @basilfx

Im currently creating an operator that uses some similar feature. But I do reference a full Kubernetes object. In that case, the EmbeddedRessource is the correct way to go. If you want to have parts of the specification, you may need to use the [PreserveUnknownFields] attribute to set that accordingly.

But as you already mentioned this in the description, what would you expect from the CRD generator here?

buehler avatar Aug 24 '21 12:08 buehler

Hi @buehler,

I'm not working on the project anymore (switched jobs).

However, what I would have expected, is that the properties under metadata are specified the same way as the properties under spec (on the same level) are. So you see that I only referenced public V1PodTemplateSpec Template { get; set; }, and it generated the spec sub-properties as expected, but the metadata properties not (it's just a type: object, nothing more).

basilfx avatar Aug 29 '21 10:08 basilfx

Ah, I guess I get it. :-) Need to investigate again.

buehler avatar Sep 09 '21 07:09 buehler

Hey, didn't want to create a separate issue, but I think it's related to this one. I've upgraded from 6.0.18 to the latest version (6.2.13). When using V1ResourceRequirements or some type that uses that built-in (for example in my case V1PersistentVolumeClaimSpec) type, the schema gets generated a bit differently and I can't use my sample.

The sample resource has the following value:

nodes:
- name: "node-1"
  productionVolumeClaimTemplate:
    accessModes:
      - "ReadWriteOnce"
    storageClassName: "ceph-fs"
    resources:
      requests:
        storage: 10Gi

The generated CRD for the volume claim template:

productionVolumeClaimTemplate:
  properties:
    ...
    resources:
      properties:
        limits:
          additionalProperties:
            properties:
              format:
                enum:
                - DecimalExponent
                - BinarySI
                - DecimalSI
                type: string
              value:
                type: string
            type: object
          type: object
        requests:
          additionalProperties:
            properties:
              format:
                enum:
                - DecimalExponent
                - BinarySI
                - DecimalSI
                type: string
              value:
                type: string
            type: object
          type: object
      type: object

And when applying the sample resource, it gives the following error: .resources.requests.storage: Invalid value: "string": productionVolumeClaimTemplate.resources.requests.storage in body must be of type object: "string"

In version 6.0.18, on the resource's limits and requests properties it generated just:

type: object
x-kubernetes-preserve-unknown-fields: true

Sorry for the mile-long text and thanks for making the awesome lib!

penumbra23 avatar Mar 17 '22 20:03 penumbra23