GoogleCloudPlatform / marketplace-k8s-app-tools

Apache License 2.0
75 stars 76 forks source link

Unknown field "spec.selector.matchLabels.app.kubernetes.io/name" on GKE 1.25 #607

Closed steven-sheehy closed 1 year ago

steven-sheehy commented 1 year ago

Attempting to install my Marketplace app on a fresh standard GKE 1.25 cluster results in the app being deployed but the deployer failing towards the end with the error strict decoding error: unknown field "spec.selector.matchLabels.app.kubernetes.io/name". Doing the exact same install on GKE 1.24 works. The chart installs fine on GKE 1.25 when deployed directly via Helm so it's not a Kubernetes deprecation issue.

The issue seems to be that the applications.app.k8s.io CRD that is installed by Marketplace is missing the additionalProperties: type: string added to the matchLabels. Adding that manually and apply the Application resource allows it to apply successfully.

$ kubectl logs mirror-deployer-mc9gm 
+ trap handle_failure EXIT
++ /bin/print_config.py --xtype NAME --values_mode raw
+ NAME=mirror
++ /bin/print_config.py --xtype NAMESPACE --values_mode raw
+ NAMESPACE=test
+ export NAME
+ export NAMESPACE
+ echo 'Deploying application "mirror"'
Deploying application "mirror"
++ kubectl get applications.app.k8s.io/mirror --namespace=test '--output=jsonpath={.metadata.uid}'
Using /opt/kubectl/1.25/kubectl (server=1.25)
+ app_uid=458df777-e0b9-4735-bc19-b996bd1ca5de
++ kubectl get applications.app.k8s.io/mirror --namespace=test '--output=jsonpath={.apiVersion}'
Using /opt/kubectl/1.25/kubectl (server=1.25)
+ app_api_version=app.k8s.io/v1beta1
+ /bin/expand_config.py --values_mode raw --app_uid 458df777-e0b9-4735-bc19-b996bd1ca5de
+ create_manifests.sh
+ [[ -z mirror ]]
+ [[ -z test ]]
+ echo 'Creating the manifests for the kubernetes resources that build the application "mirror"'
+ data_dir=/data
+ manifest_dir=/data/manifest-expanded
+ mkdir -p /data/manifest-expanded
Creating the manifests for the kubernetes resources that build the application "mirror"
+ [[ '' = \t\e\s\t ]]
+ extract_manifest /data
+ data=/data
+ extracted=/data/extracted
+ data_chart=/data/chart
+ mkdir -p /data/extracted
+ [[ -d /data/chart ]]
++ find /data/chart -maxdepth 1 -type f -name '*.tar.gz'
+ for chart in $(find "$data_chart" -maxdepth 1 -type f -name "*.tar.gz")
++ basename /data/chart/hedera-mirror-node.tar.gz
++ sed 's/.tar.gz$//'
+ chart_manifest_file=hedera-mirror-node
+ mkdir /data/extracted/hedera-mirror-node
+ tar xfC /data/chart/hedera-mirror-node.tar.gz /data/extracted/hedera-mirror-node
+ [[ '' = \t\e\s\t ]]
+ echo '=== values.yaml ==='
+ /bin/print_config.py --output=yaml
=== values.yaml ===
...omitted
+ echo ===================
===================
+ for chart in "$data_dir/extracted"/*
++ basename /data/extracted/hedera-mirror-node
++ sed 's/.tar.gz$//'
+ chart_manifest_file=hedera-mirror-node.yaml
+ helm template mirror /data/extracted/hedera-mirror-node/chart --namespace=test --values=/dev/fd/63
++ /bin/print_config.py --output=yaml
+ [[ '' != \t\e\s\t ]]
+ process_helm_hooks.py --manifest /data/manifest-expanded/hedera-mirror-node.yaml
INFO Reading /data/manifest-expanded/hedera-mirror-node.yaml
+ ensure_k8s_apps_labels.py --manifest /data/manifest-expanded/hedera-mirror-node.yaml --appname mirror
INFO Reading /data/manifest-expanded/hedera-mirror-node.yaml
+ /bin/set_ownership.py --app_name mirror --app_uid 458df777-e0b9-4735-bc19-b996bd1ca5de --app_api_version app.k8s.io/v1beta1 --manifests /data/manifest-expanded --dest /data/resources.yaml
INFO Reading /data/manifest-expanded/hedera-mirror-node.yaml
INFO Application 'mirror' owns 'PodDisruptionBudget/mirror-postgres-pgpool'
INFO Application 'mirror' owns 'Secret/mirror-grpc'
INFO Application 'mirror' owns 'Secret/mirror-importer'
INFO Application 'mirror' owns 'Secret/mirror-rest'
INFO Application 'mirror' owns 'Secret/mirror-passwords'
INFO Application 'mirror' owns 'Secret/mirror-redis'
INFO Application 'mirror' owns 'ConfigMap/mirror-postgres-postgresql-hooks-scripts'
INFO Application 'mirror' owns 'ConfigMap/mirror-init'
INFO Application 'mirror' owns 'Service/mirror-grpc'
INFO Application 'mirror' owns 'Service/mirror-postgres-pgpool'
INFO Application 'mirror' owns 'Service/mirror-postgres-postgresql-headless'
INFO Application 'mirror' owns 'Service/mirror-postgres-postgresql'
INFO Application 'mirror' owns 'Service/mirror-rest'
INFO Application 'mirror' owns 'Deployment/mirror-grpc'
INFO Application 'mirror' owns 'Deployment/mirror-importer'
INFO Application 'mirror' owns 'Deployment/mirror-postgres-pgpool'
INFO Application 'mirror' owns 'Deployment/mirror-rest'
INFO Application 'mirror' owns 'StatefulSet/mirror-postgres-postgresql'
+ validate_app_resource.py --manifests /data/resources.yaml
INFO Reading /data/resources.yaml
+ /bin/setassemblyphase.py --manifest /data/resources.yaml --status Pending
INFO Reading /data/resources.yaml
+ kubectl apply --namespace=test --filename=/data/resources.yaml
Using /opt/kubectl/1.25/kubectl (server=1.25)
poddisruptionbudget.policy/mirror-postgres-pgpool created
secret/mirror-grpc created
secret/mirror-importer created
secret/mirror-rest created
secret/mirror-passwords created
secret/mirror-redis created
configmap/mirror-postgres-postgresql-hooks-scripts created
configmap/mirror-init created
service/mirror-grpc created
service/mirror-postgres-pgpool created
service/mirror-postgres-postgresql-headless created
service/mirror-postgres-postgresql created
service/mirror-rest created
deployment.apps/mirror-grpc created
deployment.apps/mirror-importer created
deployment.apps/mirror-postgres-pgpool created
deployment.apps/mirror-rest created
statefulset.apps/mirror-postgres-postgresql created
Warning: resource applications/mirror is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
The request is invalid: patch: Invalid value: "{\"apiVersion\":\"app.k8s.io/v1beta1\",\"kind\":\"Application\",\"metadata\":{\"annotations\":{\"kubectl.kubernetes.io/last-applied-configuration\":\"{\\\"apiVersion\\\":\\\"app.k8s.io/v1beta1\\\",\\\"kind\\\":\\\"Application\\\",\\\"metadata\\\":{\\\"annotations\\\":{\\\"kubernetes-engine.cloud.google.com/icon\\\":\\\"\\\",\\\"marketplace.cloud.google.com/deploy-info\\\":\\\"{ \\\\\\\"partner_id\\\\\\\": \\\\\\\"mirror-node-public\\\\\\\", \\\\\\\"partner_name\\\\\\\": \\\\\\\"mirror-node-public\\\\\\\", \\\\\\\"product_id\\\\\\\": \\\\\\\"hedera-mirror-node\\\\\\\" }\\\"},\\\"labels\\\":{\\\"app.kubernetes.io/component\\\":\\\"hedera-mirror\\\",\\\"app.kubernetes.io/instance\\\":\\\"mirror\\\",\\\"app.kubernetes.io/managed-by\\\":\\\"Helm\\\",\\\"app.kubernetes.io/name\\\":\\\"mirror\\\",\\\"app.kubernetes.io/part-of\\\":\\\"hedera-mirror-node\\\",\\\"app.kubernetes.io/version\\\":\\\"0.74.2\\\",\\\"helm.sh/chart\\\":\\\"hedera-mirror-0.74.2\\\"},\\\"name\\\":\\\"mirror\\\",\\\"namespace\\\":\\\"test\\\"},\\\"spec\\\":{\\\"addOwnerRef\\\":true,\\\"assemblyPhase\\\":\\\"Pending\\\",\\\"componentKinds\\\":[{\\\"group\\\":\\\"v1\\\",\\\"kind\\\":\\\"ConfigMap\\\"},{\\\"group\\\":\\\"apps/v1\\\",\\\"kind\\\":\\\"Deployment\\\"},{\\\"group\\\":\\\"v1\\\",\\\"kind\\\":\\\"Pod\\\"},{\\\"group\\\":\\\"policy/v1\\\",\\\"kind\\\":\\\"PodDisruptionBudget\\\"},{\\\"group\\\":\\\"v1\\\",\\\"kind\\\":\\\"Secret\\\"},{\\\"group\\\":\\\"v1\\\",\\\"kind\\\":\\\"Service\\\"},{\\\"group\\\":\\\"apps/v1\\\",\\\"kind\\\":\\\"StatefulSet\\\"}],\\\"descriptor\\\":{\\\"description\\\":\\\"Hedera Mirror Node mirrors transaction data from Hedera nodes and serves it via GRPC and REST APIs\\\",\\\"icons\\\":[{\\\"size\\\":\\\"786x162\\\",\\\"src\\\":\\\"https://camo.githubusercontent.com/cca6b767847bb8ca5c7059481ba13a5fc81c5938/68747470733a2f2f7777772e6865646572612e636f6d2f6c6f676f2d6361706974616c2d686261722d776f72646d61726b2e6a7067\\\",\\\"type\\\":\\\"image/jpeg\\\"}],\\\"keywords\\\":[\\\"blockchain\\\",\\\"dlt\\\",\\\"hedera\\\",\\\"hashgraph\\\",\\\"mirror\\\"],\\\"links\\\":[{\\\"description\\\":\\\"Discord\\\",\\\"url\\\":\\\"https://hedera.com/discord\\\"},{\\\"description\\\":\\\"Documentation\\\",\\\"url\\\":\\\"https://docs.hedera.com\\\"},{\\\"description\\\":\\\"Source Repository\\\",\\\"url\\\":\\\"https://github.com/hashgraph/hedera-mirror-node\\\"},{\\\"description\\\":\\\"User Guide\\\",\\\"url\\\":\\\"https://github.com/hashgraph/hedera-mirror-node/blob/main/charts/marketplace/gcp/README.md\\\"},{\\\"description\\\":\\\"Website\\\",\\\"url\\\":\\\"https://hedera.com\\\"}],\\\"maintainers\\\":[{\\\"email\\\":\\\"mirrornode@hedera.com\\\",\\\"name\\\":\\\"Hedera Mirror Node Team\\\"}],\\\"notes\\\":\\\"To access the GRPC API:\\\\n\\\\n  GRPC_IP=$(kubectl get service/mirror-grpc -n test -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\\\\n\\\\n  grpcurl -plaintext \\\\\\\"${GRPC_IP}:5600\\\\\\\" list\\\\n\\\\nTo access the REST API:\\\\n\\\\n  REST_IP=$(kubectl get service/mirror-rest -n test -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\\\\n\\\\n  curl -s \\\\\\\"http://${REST_IP}/api/v1/transactions?limit=1\\\\\\\"\\\\n\\\\ntype: hedera-mirror-node\\\\n\\\",\\\"version\\\":\\\"0.74.2\\\"},\\\"selector\\\":{\\\"matchLabels\\\":{\\\"app.kubernetes.io/name\\\":\\\"mirror\\\"}}}}\\n\",\"kubernetes-engine.cloud.google.com/icon\":\"\",\"marketplace.cloud.google.com/deploy-info\":\"{ \\\"partner_id\\\": \\\"mirror-node-public\\\", \\\"partner_name\\\": \\\"mirror-node-public\\\", \\\"product_id\\\": \\\"hedera-mirror-node\\\" }\"},\"creationTimestamp\":\"2023-02-17T04:07:12Z\",\"generation\":1,\"labels\":{\"app.kubernetes.io/component\":\"hedera-mirror\",\"app.kubernetes.io/instance\":\"mirror\",\"app.kubernetes.io/managed-by\":\"Helm\",\"app.kubernetes.io/name\":\"mirror\",\"app.kubernetes.io/part-of\":\"hedera-mirror-node\",\"app.kubernetes.io/version\":\"0.74.2\",\"helm.sh/chart\":\"hedera-mirror-0.74.2\"},\"managedFields\":[{\"apiVersion\":\"app.k8s.io/v1beta1\",\"fieldsType\":\"FieldsV1\",\"fieldsV1\":{\"f:spec\":{\".\":{},\"f:assemblyPhase\":{},\"f:componentKinds\":{},\"f:selector\":{\".\":{},\"f:matchLabels\":{}}}},\"manager\":\"GoogleCloudConsole\",\"operation\":\"Update\",\"time\":\"2023-02-17T04:07:12Z\"}],\"name\":\"mirror\",\"namespace\":\"test\",\"resourceVersion\":\"365405\",\"uid\":\"458df777-e0b9-4735-bc19-b996bd1ca5de\"},\"spec\":{\"addOwnerRef\":true,\"assemblyPhase\":\"Pending\",\"componentKinds\":[{\"group\":\"v1\",\"kind\":\"ConfigMap\"},{\"group\":\"apps/v1\",\"kind\":\"Deployment\"},{\"group\":\"v1\",\"kind\":\"Pod\"},{\"group\":\"policy/v1\",\"kind\":\"PodDisruptionBudget\"},{\"group\":\"v1\",\"kind\":\"Secret\"},{\"group\":\"v1\",\"kind\":\"Service\"},{\"group\":\"apps/v1\",\"kind\":\"StatefulSet\"}],\"descriptor\":{\"description\":\"Hedera Mirror Node mirrors transaction data from Hedera nodes and serves it via GRPC and REST APIs\",\"icons\":[{\"size\":\"786x162\",\"src\":\"https://camo.githubusercontent.com/cca6b767847bb8ca5c7059481ba13a5fc81c5938/68747470733a2f2f7777772e6865646572612e636f6d2f6c6f676f2d6361706974616c2d686261722d776f72646d61726b2e6a7067\",\"type\":\"image/jpeg\"}],\"keywords\":[\"blockchain\",\"dlt\",\"hedera\",\"hashgraph\",\"mirror\"],\"links\":[{\"description\":\"Discord\",\"url\":\"https://hedera.com/discord\"},{\"description\":\"Documentation\",\"url\":\"https://docs.hedera.com\"},{\"description\":\"Source Repository\",\"url\":\"https://github.com/hashgraph/hedera-mirror-node\"},{\"description\":\"User Guide\",\"url\":\"https://github.com/hashgraph/hedera-mirror-node/blob/main/charts/marketplace/gcp/README.md\"},{\"description\":\"Website\",\"url\":\"https://hedera.com\"}],\"maintainers\":[{\"email\":\"mirrornode@hedera.com\",\"name\":\"Hedera Mirror Node Team\"}],\"notes\":\"To access the GRPC API:\\n\\n  GRPC_IP=$(kubectl get service/mirror-grpc -n test -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\\n\\n  grpcurl -plaintext \\\"${GRPC_IP}:5600\\\" list\\n\\nTo access the REST API:\\n\\n  REST_IP=$(kubectl get service/mirror-rest -n test -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\\n\\n  curl -s \\\"http://${REST_IP}/api/v1/transactions?limit=1\\\"\\n\\ntype: hedera-mirror-node\\n\",\"version\":\"0.74.2\"},\"selector\":{\"matchLabels\":{\"app.kubernetes.io/name\":\"mirror\"}}}}": strict decoding error: unknown field "spec.selector.matchLabels.app.kubernetes.io/name"
+ handle_failure
+ code=1
+ [[ -z mirror ]]
+ [[ -z test ]]
+ patch_assembly_phase.sh --status=Failed
+ for i in "$@"
+ case $i in
+ status=Failed
+ shift
+ [[ -z Failed ]]
+ [[ Failed =~ ^(Pending|Success|Failed)$ ]]
+ [[ -z mirror ]]
+ [[ -z test ]]
+ echo 'Marking deployment of application "mirror" as "Failed".'
+ [[ Failed == \S\u\c\c\e\s\s ]]
Marking deployment of application "mirror" as "Failed".
+ kubectl patch applications.app.k8s.io/mirror --output=json --namespace=test --type=merge --patch '{"spec": {"assemblyPhase": "Failed"}}'
Using /opt/kubectl/1.25/kubectl (server=1.25)
{
    "apiVersion": "app.k8s.io/v1beta1",
    "kind": "Application",
    "metadata": {
        "creationTimestamp": "2023-02-17T04:07:12Z",
        "generation": 2,
        "name": "mirror",
        "namespace": "test",
        "resourceVersion": "365579",
        "uid": "458df777-e0b9-4735-bc19-b996bd1ca5de"
    },
    "spec": {
        "assemblyPhase": "Failed",
        "componentKinds": [
            {
                "group": "",
                "kind": "ConfigMap"
            },
            {
                "group": "",
                "kind": "Secret"
            },
            {
                "group": "",
                "kind": "ServiceAccount"
            },
            {
                "group": "rbac.authorization.k8s.io",
                "kind": "Role"
            },
            {
                "group": "rbac.authorization.k8s.io",
                "kind": "RoleBinding"
            },
            {
                "group": "batch",
                "kind": "Job"
            }
        ],
        "selector": {
            "matchLabels": {}
        }
    }
}
+ exit 1

The Application resource looks correct to me:

apiVersion: app.k8s.io/v1beta1
kind: Application
metadata:
  annotations:
    kubernetes-engine.cloud.google.com/icon: omitted
    marketplace.cloud.google.com/deploy-info: '{ "partner_id": "mirror-node-public",
      "partner_name": "mirror-node-public", "product_id": "hedera-mirror-node" }'
  labels:
    app.kubernetes.io/component: hedera-mirror
    app.kubernetes.io/instance: test
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: test
    app.kubernetes.io/part-of: hedera-mirror-node
    app.kubernetes.io/version: 0.74.2
    helm.sh/chart: hedera-mirror-0.74.2
  name: test
  namespace: test3
spec:
  addOwnerRef: true
  assemblyPhase: Pending
  componentKinds:
  - group: v1
    kind: ConfigMap
  - group: apps/v1
    kind: Deployment
  - group: v1
    kind: Pod
  - group: policy/v1
    kind: PodDisruptionBudget
  - group: v1
    kind: Secret
  - group: v1
    kind: Service
  - group: apps/v1
    kind: StatefulSet
  descriptor:
    description: Hedera Mirror Node mirrors transaction data from Hedera nodes and
      serves it via GRPC and REST APIs
    icons:
    - size: 786x162
      src: https://camo.githubusercontent.com/cca6b767847bb8ca5c7059481ba13a5fc81c5938/68747470733a2f2f7777772e6865646572612e636f6d2f6c6f676f2d6361706974616c2d686261722d776f72646d61726b2e6a7067
      type: image/jpeg
    keywords:
    - blockchain
    - dlt
    - hedera
    - hashgraph
    - mirror
    links:
    - description: Discord
      url: https://hedera.com/discord
    - description: Documentation
      url: https://docs.hedera.com
    - description: Source Repository
      url: https://github.com/hashgraph/hedera-mirror-node
    - description: User Guide
      url: https://github.com/hashgraph/hedera-mirror-node/blob/main/charts/marketplace/gcp/README.md
    - description: Website
      url: https://hedera.com
    maintainers:
    - email: mirrornode@hedera.com
      name: Hedera Mirror Node Team
    notes: "To access the GRPC API:\n\n  GRPC_IP=$(kubectl get service/test-grpc -n\
      \ test3 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\n\n  grpcurl -plaintext\
      \ \"${GRPC_IP}:5600\" list\n\nTo access the REST API:\n\n  REST_IP=$(kubectl\
      \ get service/test-rest -n test3 -o jsonpath='{.status.loadBalancer.ingress[0].ip}')\n\
      \n  curl -s \"http://${REST_IP}/api/v1/transactions?limit=1\"\n\ntype: hedera-mirror-node\n"
    version: 0.74.2
  selector:
    matchLabels:
      app.kubernetes.io/name: test

CRD deployed by marketplace:

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  annotations:
    api-approved.kubernetes.io: https://github.com/kubernetes-sigs/application/pull/2
    controller-gen.kubebuilder.io/version: v0.4.0
  creationTimestamp: "2023-02-17T04:07:10Z"
  generation: 1
  name: applications.app.k8s.io
  resourceVersion: "365385"
  uid: 6437de80-2446-407b-87a0-c264175a8afd
spec:
  conversion:
    strategy: None
  group: app.k8s.io
  names:
    categories:
    - all
    kind: Application
    listKind: ApplicationList
    plural: applications
    shortNames:
    - app
    singular: application
  scope: Namespaced
  versions:
  - name: v1beta1
    schema:
      openAPIV3Schema:
        description: Application is the Schema for the applications API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: ApplicationSpec defines the specification for an Application.
            properties:
              addOwnerRef:
                description: AddOwnerRef objects - flag to indicate if we need to
                  add OwnerRefs to matching objects Matching is done by using Selector
                  to query all ComponentGroupKinds
                type: boolean
              assemblyPhase:
                description: AssemblyPhase represents the current phase of the application's
                  assembly. An empty value is equivalent to "Succeeded".
                type: string
              componentKinds:
                description: ComponentGroupKinds is a list of Kinds for Application's
                  components (e.g. Deployments, Pods, Services, CRDs). It can be used
                  in conjunction with the Application's Selector to list or watch
                  the Applications components.
                items:
                  description: GroupKind specifies a Group and a Kind, but does not
                    force a version.  This is useful for identifying concepts during
                    lookup stages without having partially valid types
                  properties:
                    group:
                      type: string
                    kind:
                      type: string
                  required:
                  - group
                  - kind
                  type: object
                type: array
              descriptor:
                description: Descriptor regroups information and metadata about an
                  application.
                properties:
                  description:
                    description: Description is a brief string description of the
                      Application.
                    type: string
                  icons:
                    description: Icons is an optional list of icons for an application.
                      Icon information includes the source, size, and mime type.
                    items:
                      description: ImageSpec contains information about an image used
                        as an icon.
                      properties:
                        size:
                          description: (optional) The size of the image in pixels
                            (e.g., 25x25).
                          type: string
                        src:
                          description: The source for image represented as either
                            an absolute URL to the image or a Data URL containing
                            the image. Data URLs are defined in RFC 2397.
                          type: string
                        type:
                          description: (optional) The mine type of the image (e.g.,
                            "image/png").
                          type: string
                      required:
                      - src
                      type: object
                    type: array
                  keywords:
                    description: Keywords is an optional list of key words associated
                      with the application (e.g. MySQL, RDBMS, database).
                    items:
                      type: string
                    type: array
                  links:
                    description: Links are a list of descriptive URLs intended to
                      be used to surface additional documentation, dashboards, etc.
                    items:
                      description: Link contains information about an URL to surface
                        documentation, dashboards, etc.
                      properties:
                        description:
                          description: Description is human readable content explaining
                            the purpose of the link.
                          type: string
                        url:
                          description: Url typically points at a website address.
                          type: string
                      type: object
                    type: array
                  maintainers:
                    description: Maintainers is an optional list of maintainers of
                      the application. The maintainers in this list maintain the the
                      source code, images, and package for the application.
                    items:
                      description: ContactData contains information about an individual
                        or organization.
                      properties:
                        email:
                          description: Email is the email address.
                          type: string
                        name:
                          description: Name is the descriptive name.
                          type: string
                        url:
                          description: Url could typically be a website address.
                          type: string
                      type: object
                    type: array
                  notes:
                    description: Notes contain a human readable snippets intended
                      as a quick start for the users of the Application. CommonMark
                      markdown syntax may be used for rich text representation.
                    type: string
                  owners:
                    description: Owners is an optional list of the owners of the installed
                      application. The owners of the application should be contacted
                      in the event of a planned or unplanned disruption affecting
                      the application.
                    items:
                      description: ContactData contains information about an individual
                        or organization.
                      properties:
                        email:
                          description: Email is the email address.
                          type: string
                        name:
                          description: Name is the descriptive name.
                          type: string
                        url:
                          description: Url could typically be a website address.
                          type: string
                      type: object
                    type: array
                  type:
                    description: Type is the type of the application (e.g. WordPress,
                      MySQL, Cassandra).
                    type: string
                  version:
                    description: Version is an optional version indicator for the
                      Application.
                    type: string
                type: object
              info:
                description: Info contains human readable key,value pairs for the
                  Application.
                items:
                  description: InfoItem is a human readable key,value pair containing
                    important information about how to access the Application.
                  properties:
                    name:
                      description: Name is a human readable title for this piece of
                        information.
                      type: string
                    type:
                      description: Type of the value for this InfoItem.
                      type: string
                    value:
                      description: Value is human readable content.
                      type: string
                    valueFrom:
                      description: ValueFrom defines a reference to derive the value
                        from another source.
                      properties:
                        configMapKeyRef:
                          description: Selects a key of a ConfigMap.
                          properties:
                            apiVersion:
                              description: API version of the referent.
                              type: string
                            fieldPath:
                              description: 'If referring to a piece of an object instead
                                of an entire object, this string should contain a
                                valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
                                For example, if the object reference is to a container
                                within a pod, this would take on a value like: "spec.containers{name}"
                                (where "name" refers to the name of the container
                                that triggered the event) or if no container name
                                is specified "spec.containers[2]" (container with
                                index 2 in this pod). This syntax is chosen only to
                                have some well-defined way of referencing a part of
                                an object. TODO: this design is not final and this
                                field is subject to change in the future.'
                              type: string
                            key:
                              description: The key to select.
                              type: string
                            kind:
                              description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                              type: string
                            name:
                              description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                              type: string
                            namespace:
                              description: 'Namespace of the referent. More info:
                                https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
                              type: string
                            resourceVersion:
                              description: 'Specific resourceVersion to which this
                                reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
                              type: string
                            uid:
                              description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
                              type: string
                          type: object
                        ingressRef:
                          description: Select an Ingress.
                          properties:
                            apiVersion:
                              description: API version of the referent.
                              type: string
                            fieldPath:
                              description: 'If referring to a piece of an object instead
                                of an entire object, this string should contain a
                                valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
                                For example, if the object reference is to a container
                                within a pod, this would take on a value like: "spec.containers{name}"
                                (where "name" refers to the name of the container
                                that triggered the event) or if no container name
                                is specified "spec.containers[2]" (container with
                                index 2 in this pod). This syntax is chosen only to
                                have some well-defined way of referencing a part of
                                an object. TODO: this design is not final and this
                                field is subject to change in the future.'
                              type: string
                            host:
                              description: The optional host to select.
                              type: string
                            kind:
                              description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                              type: string
                            name:
                              description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                              type: string
                            namespace:
                              description: 'Namespace of the referent. More info:
                                https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
                              type: string
                            path:
                              description: The optional HTTP path.
                              type: string
                            protocol:
                              description: Protocol for the ingress
                              type: string
                            resourceVersion:
                              description: 'Specific resourceVersion to which this
                                reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
                              type: string
                            uid:
                              description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
                              type: string
                          type: object
                        secretKeyRef:
                          description: Selects a key of a Secret.
                          properties:
                            apiVersion:
                              description: API version of the referent.
                              type: string
                            fieldPath:
                              description: 'If referring to a piece of an object instead
                                of an entire object, this string should contain a
                                valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
                                For example, if the object reference is to a container
                                within a pod, this would take on a value like: "spec.containers{name}"
                                (where "name" refers to the name of the container
                                that triggered the event) or if no container name
                                is specified "spec.containers[2]" (container with
                                index 2 in this pod). This syntax is chosen only to
                                have some well-defined way of referencing a part of
                                an object. TODO: this design is not final and this
                                field is subject to change in the future.'
                              type: string
                            key:
                              description: The key to select.
                              type: string
                            kind:
                              description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                              type: string
                            name:
                              description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                              type: string
                            namespace:
                              description: 'Namespace of the referent. More info:
                                https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
                              type: string
                            resourceVersion:
                              description: 'Specific resourceVersion to which this
                                reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
                              type: string
                            uid:
                              description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
                              type: string
                          type: object
                        serviceRef:
                          description: Select a Service.
                          properties:
                            apiVersion:
                              description: API version of the referent.
                              type: string
                            fieldPath:
                              description: 'If referring to a piece of an object instead
                                of an entire object, this string should contain a
                                valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
                                For example, if the object reference is to a container
                                within a pod, this would take on a value like: "spec.containers{name}"
                                (where "name" refers to the name of the container
                                that triggered the event) or if no container name
                                is specified "spec.containers[2]" (container with
                                index 2 in this pod). This syntax is chosen only to
                                have some well-defined way of referencing a part of
                                an object. TODO: this design is not final and this
                                field is subject to change in the future.'
                              type: string
                            kind:
                              description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                              type: string
                            name:
                              description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                              type: string
                            namespace:
                              description: 'Namespace of the referent. More info:
                                https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
                              type: string
                            path:
                              description: The optional HTTP path.
                              type: string
                            port:
                              description: The optional port to select.
                              format: int32
                              type: integer
                            protocol:
                              description: Protocol for the service
                              type: string
                            resourceVersion:
                              description: 'Specific resourceVersion to which this
                                reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
                              type: string
                            uid:
                              description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
                              type: string
                          type: object
                        type:
                          description: Type of source.
                          type: string
                      type: object
                  type: object
                type: array
              selector:
                description: 'Selector is a label query over kinds that created by
                  the application. It must match the component objects'' labels. More
                  info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors'
                properties:
                  matchExpressions:
                    description: matchExpressions is a list of label selector requirements.
                      The requirements are ANDed.
                    items:
                      description: A label selector requirement is a selector that
                        contains values, a key, and an operator that relates the key
                        and values.
                      properties:
                        key:
                          description: key is the label key that the selector applies
                            to.
                          type: string
                        operator:
                          description: operator represents a key's relationship to
                            a set of values. Valid operators are In, NotIn, Exists
                            and DoesNotExist.
                          type: string
                        values:
                          description: values is an array of string values. If the
                            operator is In or NotIn, the values array must be non-empty.
                            If the operator is Exists or DoesNotExist, the values
                            array must be empty. This array is replaced during a strategic
                            merge patch.
                          items:
                            type: string
                          type: array
                      required:
                      - key
                      - operator
                      type: object
                    type: array
                  matchLabels:
                    description: matchLabels is a map of {key,value} pairs. A single
                      {key,value} in the matchLabels map is equivalent to an element
                      of matchExpressions, whose key field is "key", the operator
                      is "In", and the values array contains only "value". The requirements
                      are ANDed.
                    type: object
                type: object
            type: object
          status:
            description: ApplicationStatus defines controller's the observed state
              of Application
            properties:
              components:
                description: Object status array for all matching objects
                items:
                  description: ObjectStatus is a generic status holder for objects
                  properties:
                    group:
                      description: Object group
                      type: string
                    kind:
                      description: Kind of object
                      type: string
                    link:
                      description: Link to object
                      type: string
                    name:
                      description: Name of object
                      type: string
                    status:
                      description: 'Status. Values: InProgress, Ready, Unknown'
                      type: string
                  type: object
                type: array
              componentsReady:
                description: 'ComponentsReady: status of the components in the format
                  ready/total'
                type: string
              conditions:
                description: Conditions represents the latest state of the object
                items:
                  description: Condition describes the state of an object at a certain
                    point.
                  properties:
                    lastTransitionTime:
                      description: Last time the condition transitioned from one status
                        to another.
                      format: date-time
                      type: string
                    lastUpdateTime:
                      description: Last time the condition was probed
                      format: date-time
                      type: string
                    message:
                      description: A human readable message indicating details about
                        the transition.
                      type: string
                    reason:
                      description: The reason for the condition's last transition.
                      type: string
                    status:
                      description: Status of the condition, one of True, False, Unknown.
                      type: string
                    type:
                      description: Type of condition.
                      type: string
                  required:
                  - status
                  - type
                  type: object
                type: array
              observedGeneration:
                description: ObservedGeneration is the most recent generation observed.
                  It corresponds to the Object's generation, which is updated on mutation
                  by the API Server.
                format: int64
                type: integer
            type: object
        type: object
    served: true
    storage: true
    subresources:
      status: {}
  - name: v1alpha1
    schema:
      openAPIV3Schema:
        description: Application is the Schema for the applications API
        properties:
          apiVersion:
            description: 'APIVersion defines the versioned schema of this representation
              of an object. Servers should convert recognized schemas to the latest
              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
            type: string
          kind:
            description: 'Kind is a string value representing the REST resource this
              object represents. Servers may infer this from the endpoint the client
              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
            type: string
          metadata:
            type: object
          spec:
            description: ApplicationSpec defines the specification for an Application.
            properties:
              assemblyPhase:
                type: string
              componentKinds:
                description: ComponentGroupKinds is a list of Kinds for Application's
                  components (e.g. Deployments, Pods, Services, CRDs). It can be used
                  in conjunction with the Application's Selector to list or watch
                  the Applications components.
                items:
                  description: GroupKind specifies a Group and a Kind, but does not
                    force a version.  This is useful for identifying concepts during
                    lookup stages without having partially valid types
                  properties:
                    group:
                      type: string
                    kind:
                      type: string
                  type: object
                type: array
              description:
                type: string
              info:
                description: Info contains human readable key,value pairs for the
                  Application.
                items:
                  description: InfoItem is a human readable key,value pair containing
                    important information about how to access the Application.
                  properties:
                    name:
                      description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                      type: string
                    value:
                      type: string
                  type: object
                type: array
              keywords:
                items:
                  type: string
                type: array
              links:
                items:
                  properties:
                    description:
                      type: string
                    url:
                      type: string
                  type: object
                type: array
              maintainers:
                items:
                  properties:
                    email:
                      type: string
                    name:
                      type: string
                    url:
                      type: string
                  type: object
                type: array
              notes:
                type: string
              owners:
                items:
                  type: string
                type: array
              selector:
                properties:
                  matchExpressions:
                    items:
                      properties:
                        key:
                          type: string
                        operator:
                          type: string
                        values:
                          items:
                            type: string
                          type: array
                      type: object
                    type: array
                  matchLabels:
                    type: object
                type: object
              type:
                type: string
              version:
                type: string
            type: object
          status:
            properties:
              observedGeneration:
                type: integer
            type: object
        type: object
    served: false
    storage: false
status:
  acceptedNames:
    categories:
    - all
    kind: Application
    listKind: ApplicationList
    plural: applications
    shortNames:
    - app
    singular: application
  conditions:
  - lastTransitionTime: "2023-02-17T04:07:10Z"
    message: no conflicts found
    reason: NoConflicts
    status: "True"
    type: NamesAccepted
  - lastTransitionTime: "2023-02-17T04:07:10Z"
    message: the initial names have been accepted
    reason: InitialNamesAccepted
    status: "True"
    type: Established
  - lastTransitionTime: "2023-02-17T04:07:10Z"
    message: approved in https://github.com/kubernetes-sigs/application/pull/2
    reason: ApprovedAnnotation
    status: "True"
    type: KubernetesAPIApprovalPolicyConformant
  storedVersions:
  - v1beta1
gibbleyg commented 1 year ago

Thanks for the report. The issue here is that the Application CRD deployed by the UI is missing additionalProperties which allows an object to have arbitrary key-value pairs. This appears to surface in 1.25 due to KEP-2885 being enabled.

We're working on a fix to address this

gibbleyg commented 1 year ago

Fix is in production UI and LGTM.