From c5e2d55847a0ab162fbf3857a48b6eecd7496f2f Mon Sep 17 00:00:00 2001 From: Rui Fu Date: Mon, 8 Sep 2025 15:48:09 +0800 Subject: [PATCH 1/7] copy crds --- .../resource.streamnative.io_apikeys.yaml | 232 ++++++++++++++ ...rce.streamnative.io_pulsarconnections.yaml | 13 +- ...streamnative.io_pulsargeoreplications.yaml | 48 +++ ...urce.streamnative.io_pulsarnamespaces.yaml | 273 ++++++++++++++++ ...resource.streamnative.io_pulsartopics.yaml | 294 +++++++++++++++++- ...resource.streamnative.io_rolebindings.yaml | 255 +++++++++++++++ ...treamnative.io_serviceaccountbindings.yaml | 193 ++++++++++++ ...ource.streamnative.io_serviceaccounts.yaml | 175 +++++++++++ .../templates/role.yaml | 104 +++++++ 9 files changed, 1580 insertions(+), 7 deletions(-) create mode 100644 charts/pulsar-resources-operator/crds/resource.streamnative.io_apikeys.yaml create mode 100644 charts/pulsar-resources-operator/crds/resource.streamnative.io_rolebindings.yaml create mode 100644 charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccountbindings.yaml create mode 100644 charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccounts.yaml diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_apikeys.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_apikeys.yaml new file mode 100644 index 00000000..229c1597 --- /dev/null +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_apikeys.yaml @@ -0,0 +1,232 @@ +# Copyright 2025 StreamNative +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: apikeys.resource.streamnative.io +spec: + group: resource.streamnative.io + names: + categories: + - streamnative + - all + kind: APIKey + listKind: APIKeyList + plural: apikeys + singular: apikey + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: READY + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: APIKey is the Schema for the APIKeys 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: APIKeySpec defines the desired state of APIKey + properties: + apiServerRef: + description: APIServerRef is the reference to the StreamNativeCloudConnection + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + type: object + x-kubernetes-map-type: atomic + description: + description: Description is a user defined description of the key + type: string + encryptionKey: + description: EncryptionKey contains the public key used to encrypt + the token + properties: + pem: + description: PEM is the public key in PEM format + type: string + type: object + x-kubernetes-map-type: atomic + expirationTime: + description: |- + ExpirationTime is a timestamp that defines when this API key will expire + This can only be set on initial creation and not updated later + format: date-time + type: string + exportPlaintextToken: + description: ExportPlaintextToken indicates whether the token should + be exported in plaintext + type: boolean + instanceName: + description: InstanceName is the name of the instance this API key + is for + type: string + revoke: + description: Revoke indicates whether this API key should be revoked + type: boolean + serviceAccountName: + description: ServiceAccountName is the name of the service account + this API key is for + type: string + required: + - apiServerRef + type: object + status: + description: APIKeyStatus defines the observed state of APIKey + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + encryptedToken: + description: EncryptedToken is the encrypted security token issued + for the key + properties: + jwe: + description: |- + JWE is the token as a JSON Web Encryption (JWE) message + For RSA public keys, the key encryption algorithm is RSA-OAEP, and the content encryption algorithm is AES GCM + type: string + type: object + x-kubernetes-map-type: atomic + expiresAt: + description: ExpiresAt is a timestamp of when the key expires + format: date-time + type: string + issuedAt: + description: IssuedAt is a timestamp of when the key was issued + format: date-time + type: string + keyId: + description: KeyID is a generated field that is a uid for the token + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation + format: int64 + type: integer + revokedAt: + description: RevokedAt is a timestamp of when the key was revoked, + it triggers revocation action + format: date-time + type: string + token: + description: Token is the plaintext security token issued for the + key + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarconnections.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarconnections.yaml index e99ef70c..e9864203 100644 --- a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarconnections.yaml +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarconnections.yaml @@ -224,15 +224,18 @@ spec: ClusterName specifies the name of the local Pulsar cluster. When setting up Geo-Replication between Pulsar instances, this should be enabled to identify the cluster. type: string + tlsAllowInsecureConnection: + description: TLSAllowInsecureConnection indicates whether to allow + insecure connection to the broker. + type: boolean tlsEnableHostnameVerification: - description: TLSEnableHostnameVerification indicates whether to verify the hostname of the broker. + description: |- + TLSEnableHostnameVerification indicates whether to verify the hostname of the broker. Only used when using secure urls. type: boolean - tlsAllowInsecureConnection: - description: TLSAllowInsecureConnection indicates whether to allow insecure connection to the broker. - type: boolean tlsTrustCertsFilePath: - description: TLSTrustCertsFilePath Path for the TLS certificate used to validate the broker endpoint when using TLS. + description: TLSTrustCertsFilePath Path for the TLS certificate used + to validate the broker endpoint when using TLS. type: string type: object status: diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsargeoreplications.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsargeoreplications.yaml index 9caa28a5..ee30cfc5 100644 --- a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsargeoreplications.yaml +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsargeoreplications.yaml @@ -54,6 +54,54 @@ spec: spec: description: PulsarGeoReplicationSpec defines the desired state of PulsarGeoReplication properties: + clusterParamsOverride: + description: |- + ClusterParamsOverride allows overriding specific cluster parameters when setting up + geo-replication. This is useful when the destination cluster requires different + configuration than what's defined in the DestinationConnectionRef. + properties: + authentication: + description: |- + Authentication overrides the authentication configuration for the cluster. + When this field is set, the secret update check will be skipped for this geo-replication. + properties: + authParameters: + description: |- + AuthParameters contains the authentication parameters as a string. + Format depends on the AuthPlugin: + - For Token: "token:your-token-here" + - For Token: "file://your-token-file-path-on-brokers" + - For OAuth2: JSON string with client credentials + type: string + authPlugin: + description: |- + AuthPlugin specifies the authentication plugin class name + Common values: "org.apache.pulsar.client.impl.auth.AuthenticationToken", + "org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2" + type: string + type: object + brokerClientTrustCertsFilePath: + description: |- + BrokerClientTrustCertsFilePath overrides the file path to the trusted TLS certificate + for outgoing connections to Pulsar brokers + type: string + brokerServiceSecureURL: + description: BrokerServiceSecureURL overrides the TLS-enabled + URL for secure connections to Pulsar brokers + type: string + brokerServiceURL: + description: BrokerServiceURL overrides the non-TLS URL for connecting + to Pulsar brokers + type: string + serviceSecureURL: + description: ServiceSecureURL overrides the HTTPS URL for secure + connections to the Pulsar admin service + type: string + serviceURL: + description: ServiceURL overrides the HTTP(S) URL for the Pulsar + cluster's admin service + type: string + type: object connectionRef: description: ConnectionRef is the reference to the source PulsarConnection properties: diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarnamespaces.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarnamespaces.yaml index 7fc2ea5f..b9dbd19b 100644 --- a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarnamespaces.yaml +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsarnamespaces.yaml @@ -76,6 +76,11 @@ spec: PulsarNamespaceSpec defines the desired state of a Pulsar namespace. It corresponds to the configuration options available in Pulsar's namespace admin API. properties: + antiAffinityGroup: + description: |- + AntiAffinityGroup specifies the anti-affinity group for this namespace. + Namespaces in the same anti-affinity group will be placed on different brokers. + type: string backlogQuotaLimitSize: anyOf: - type: integer @@ -120,6 +125,12 @@ spec: This affects how the namespace is distributed across the cluster. format: int32 type: integer + compactionThreshold: + description: |- + CompactionThreshold sets the compaction threshold for topics in this namespace. + Topics will be compacted when they reach this size threshold (in bytes). + format: int64 + type: integer connectionRef: description: |- ConnectionRef is the reference to the PulsarConnection resource @@ -142,6 +153,36 @@ spec: description: Deduplication controls whether to enable message deduplication for the namespace. type: boolean + dispatchRate: + description: |- + DispatchRate sets the message dispatch rate for topics in this namespace. + This controls how fast messages are delivered to consumers. + properties: + dispatchThrottlingRateInByte: + description: |- + DispatchThrottlingRateInByte specifies the maximum number of bytes per second allowed + -1 means unlimited + format: int64 + type: integer + dispatchThrottlingRateInMsg: + description: |- + DispatchThrottlingRateInMsg specifies the maximum number of messages per second allowed + -1 means unlimited + format: int32 + type: integer + ratePeriodInSecond: + default: 1 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + type: object + encryptionRequired: + description: |- + EncryptionRequired specifies whether message encryption is required for this namespace. + When enabled, all messages published to topics in this namespace must be encrypted. + type: boolean geoReplicationRefs: description: |- GeoReplicationRefs is a list of references to PulsarGeoReplication resources, @@ -168,6 +209,35 @@ spec: type: object x-kubernetes-map-type: atomic type: array + inactiveTopicPolicies: + description: |- + InactiveTopicPolicies sets the policies for handling inactive topics in this namespace. + This controls automatic cleanup of unused topics. + properties: + deleteWhileInactive: + description: DeleteWhileInactive specifies whether to delete topics + while they are inactive + type: boolean + inactiveTopicDeleteMode: + description: |- + InactiveTopicDeleteMode specifies how inactive topics should be handled + Valid values: "delete_when_no_subscriptions", "delete_when_subscriptions_caught_up" + enum: + - delete_when_no_subscriptions + - delete_when_subscriptions_caught_up + type: string + maxInactiveDurationInSeconds: + description: MaxInactiveDurationInSeconds specifies how long a + topic can remain inactive before being deleted + format: int32 + minimum: 1 + type: integer + type: object + isAllowAutoUpdateSchema: + description: |- + IsAllowAutoUpdateSchema specifies whether to allow automatic schema updates. + When enabled, producers can automatically update schemas without manual approval. + type: boolean lifecyclePolicy: description: |- LifecyclePolicy determines whether to keep or delete the Pulsar namespace @@ -214,6 +284,64 @@ spec: OffloadThresholdTime specifies the time limit for message offloading. Messages older than this limit will be offloaded to the tiered storage. type: string + persistencePolicies: + description: |- + PersistencePolicies sets the persistence policies for this namespace. + This controls how data is stored and replicated in BookKeeper. + properties: + bookkeeperAckQuorum: + description: |- + BookkeeperAckQuorum specifies the number of replicas to wait for acknowledgment + Must be <= BookkeeperWriteQuorum + format: int32 + minimum: 1 + type: integer + bookkeeperEnsemble: + description: |- + BookkeeperEnsemble specifies the number of bookies to use for a ledger + This determines the replication factor for storing data + format: int32 + minimum: 1 + type: integer + bookkeeperWriteQuorum: + description: |- + BookkeeperWriteQuorum specifies the number of replicas to write for each entry + Must be <= BookkeeperEnsemble + format: int32 + minimum: 1 + type: integer + managedLedgerMaxMarkDeleteRate: + description: |- + ManagedLedgerMaxMarkDeleteRate specifies the maximum rate at which mark-delete operations can be performed + This helps control the rate of acknowledgment processing + Value should be a decimal number as string (e.g., "1.5", "2.0") + type: string + type: object + properties: + additionalProperties: + type: string + description: |- + Properties is a map of custom properties for this namespace. + These are arbitrary key-value pairs that can be used for namespace metadata. + type: object + publishRate: + description: |- + PublishRate sets the publish rate limit for producers in this namespace. + This controls how fast producers can publish messages. + properties: + publishThrottlingRateInByte: + description: |- + PublishThrottlingRateInByte specifies the maximum number of bytes per second that producers can publish + -1 means unlimited + format: int64 + type: integer + publishThrottlingRateInMsg: + description: |- + PublishThrottlingRateInMsg specifies the maximum number of messages per second that producers can publish + -1 means unlimited + format: int32 + type: integer + type: object replicationClusters: description: |- ReplicationClusters is the list of clusters to which the namespace is replicated @@ -223,6 +351,31 @@ spec: items: type: string type: array + replicatorDispatchRate: + description: |- + ReplicatorDispatchRate sets the replicator dispatch rate for topics in this namespace. + This controls the rate at which messages are replicated across clusters. + properties: + dispatchThrottlingRateInByte: + description: |- + DispatchThrottlingRateInByte specifies the maximum number of bytes per second allowed + -1 means unlimited + format: int64 + type: integer + dispatchThrottlingRateInMsg: + description: |- + DispatchThrottlingRateInMsg specifies the maximum number of messages per second allowed + -1 means unlimited + format: int32 + type: integer + ratePeriodInSecond: + default: 1 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + type: object retentionSize: anyOf: - type: integer @@ -238,6 +391,126 @@ spec: Should be set in conjunction with RetentionSize for effective retention policy. Retention Quota must exceed configured backlog quota for namespace type: string + schemaAutoUpdateCompatibilityStrategy: + description: |- + SchemaAutoUpdateCompatibilityStrategy specifies the compatibility strategy for automatic schema updates. + This controls how schema evolution is handled when schemas are automatically updated. + enum: + - AutoUpdateDisabled + - Backward + - Forward + - Full + - AlwaysCompatible + - BackwardTransitive + - ForwardTransitive + - FullTransitive + type: string + schemaCompatibilityStrategy: + description: |- + SchemaCompatibilityStrategy defines the schema compatibility strategy for this namespace. + If not specified, the cluster's default schema compatibility strategy will be used. + This setting controls how schema evolution is handled for topics within this namespace. + enum: + - UNDEFINED + - ALWAYS_INCOMPATIBLE + - ALWAYS_COMPATIBLE + - BACKWARD + - FORWARD + - FULL + - BACKWARD_TRANSITIVE + - FORWARD_TRANSITIVE + - FULL_TRANSITIVE + type: string + schemaValidationEnforced: + description: |- + SchemaValidationEnforced controls whether schema validation is enforced for this namespace. + When enabled, producers must provide a schema when publishing messages. + If not specified, the cluster's default schema validation enforcement setting will be used. + type: boolean + subscribeRate: + description: |- + SubscribeRate sets the subscribe rate limit for consumers in this namespace. + This controls how fast consumers can subscribe to topics. + properties: + ratePeriodInSecond: + default: 30 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + subscribeThrottlingRatePerConsumer: + description: |- + SubscribeThrottlingRatePerConsumer specifies the maximum subscribe rate per consumer + -1 means unlimited + format: int32 + type: integer + type: object + subscriptionAuthMode: + description: |- + SubscriptionAuthMode specifies the subscription authentication mode for this namespace. + Valid values are "None" and "Prefix". + enum: + - None + - Prefix + type: string + subscriptionDispatchRate: + description: |- + SubscriptionDispatchRate sets the subscription dispatch rate for topics in this namespace. + This controls the rate at which subscriptions can dispatch messages. + properties: + dispatchThrottlingRateInByte: + description: |- + DispatchThrottlingRateInByte specifies the maximum number of bytes per second allowed + -1 means unlimited + format: int64 + type: integer + dispatchThrottlingRateInMsg: + description: |- + DispatchThrottlingRateInMsg specifies the maximum number of messages per second allowed + -1 means unlimited + format: int32 + type: integer + ratePeriodInSecond: + default: 1 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + type: object + subscriptionExpirationTime: + description: |- + SubscriptionExpirationTime specifies the time after which inactive subscriptions will expire. + Subscriptions that haven't consumed messages for this duration will be automatically deleted. + type: string + topicAutoCreationConfig: + description: |- + TopicAutoCreationConfig controls whether automatic topic creation is allowed in this namespace + and configures properties of automatically created topics + properties: + allow: + description: Allow specifies whether to allow automatic topic + creation + type: boolean + partitions: + description: Partitions specifies the default number of partitions + for automatically created topics + format: int32 + type: integer + type: + description: Type specifies the type of automatically created + topics + enum: + - partitioned + - non-partitioned + type: string + type: object + validateProducerName: + description: |- + ValidateProducerName specifies whether to validate producer names. + When enabled, producer names must follow specific naming conventions. + type: boolean required: - connectionRef - name diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsartopics.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsartopics.yaml index 9bc1ed9c..73a5a0b2 100644 --- a/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsartopics.yaml +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_pulsartopics.yaml @@ -79,6 +79,14 @@ spec: PulsarTopicSpec defines the desired state of PulsarTopic. It corresponds to the configuration options available in Pulsar's topic admin API. properties: + autoSubscriptionCreation: + description: |- + AutoSubscriptionCreation defines the auto subscription creation override for the topic. + This controls whether subscriptions can be created automatically. + properties: + allowAutoSubscriptionCreation: + type: boolean + type: object backlogQuotaLimitSize: anyOf: - type: integer @@ -98,6 +106,12 @@ spec: BacklogQuotaRetentionPolicy specifies the retention policy for messages when backlog quota is exceeded. Valid values are "producer_request_hold", "producer_exception", or "consumer_backlog_eviction". type: string + compactionThreshold: + description: |- + CompactionThreshold specifies the size threshold in bytes for automatic topic compaction. + When the topic reaches this size, compaction will be triggered automatically. + format: int64 + type: integer connectionRef: description: |- ConnectionRef is the reference to the PulsarConnection resource @@ -120,6 +134,52 @@ spec: description: Deduplication controls whether to enable message deduplication for the topic. type: boolean + deduplicationSnapshotInterval: + description: |- + DeduplicationSnapshotInterval specifies the interval for taking deduplication snapshots. + This affects the deduplication performance and storage overhead. + format: int32 + type: integer + delayedDelivery: + description: |- + DelayedDelivery defines the delayed delivery policy for the topic. + This allows messages to be delivered with a delay. + properties: + active: + description: Active determines whether delayed delivery is enabled + for the topic + type: boolean + tickTimeMillis: + description: TickTimeMillis specifies the tick time for delayed + message delivery in milliseconds + format: int64 + type: integer + type: object + dispatchRate: + description: |- + DispatchRate defines the message dispatch rate limiting policy for the topic. + This controls the rate at which messages are delivered to consumers. + properties: + dispatchThrottlingRateInByte: + description: |- + DispatchThrottlingRateInByte specifies the maximum number of bytes per second allowed + -1 means unlimited + format: int64 + type: integer + dispatchThrottlingRateInMsg: + description: |- + DispatchThrottlingRateInMsg specifies the maximum number of messages per second allowed + -1 means unlimited + format: int32 + type: integer + ratePeriodInSecond: + default: 1 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + type: object geoReplicationRefs: description: |- GeoReplicationRefs is a list of references to PulsarGeoReplication resources, @@ -145,6 +205,30 @@ spec: type: object x-kubernetes-map-type: atomic type: array + inactiveTopicPolicies: + description: |- + InactiveTopicPolicies defines the inactive topic cleanup policy for the topic. + This controls how inactive topics are automatically cleaned up. + properties: + deleteWhileInactive: + description: DeleteWhileInactive specifies whether to delete topics + while they are inactive + type: boolean + inactiveTopicDeleteMode: + description: |- + InactiveTopicDeleteMode specifies how inactive topics should be handled + Valid values: "delete_when_no_subscriptions", "delete_when_subscriptions_caught_up" + enum: + - delete_when_no_subscriptions + - delete_when_subscriptions_caught_up + type: string + maxInactiveDurationInSeconds: + description: MaxInactiveDurationInSeconds specifies how long a + topic can remain inactive before being deleted + format: int32 + minimum: 1 + type: integer + type: object lifecyclePolicy: description: |- LifecyclePolicy determines whether to keep or delete the Pulsar topic @@ -158,11 +242,27 @@ spec: on the topic. format: int32 type: integer + maxConsumersPerSubscription: + description: MaxConsumersPerSubscription sets the maximum number of + consumers allowed per subscription. + format: int32 + type: integer + maxMessageSize: + description: |- + MaxMessageSize specifies the maximum size of messages that can be published to the topic. + Messages larger than this size will be rejected. + format: int32 + type: integer maxProducers: description: MaxProducers sets the maximum number of producers allowed on the topic. format: int32 type: integer + maxSubscriptionsPerTopic: + description: MaxSubscriptionsPerTopic sets the maximum number of subscriptions + allowed on the topic. + format: int32 + type: integer maxUnAckedMessagesPerConsumer: description: |- MaxUnAckedMessagesPerConsumer sets the maximum number of unacknowledged @@ -183,6 +283,45 @@ spec: name: description: Name is the topic name type: string + offloadPolicies: + description: |- + OffloadPolicies defines the offload policies for the topic. + This controls how data is offloaded to external storage systems. + properties: + managedLedgerOffloadAutoTriggerSizeThresholdBytes: + format: int64 + type: integer + managedLedgerOffloadDeletionLagInMillis: + format: int64 + type: integer + managedLedgerOffloadDriver: + type: string + managedLedgerOffloadDriverMetadata: + additionalProperties: + type: string + type: object + managedLedgerOffloadMaxThreads: + type: integer + managedLedgerOffloadThresholdInBytes: + format: int64 + type: integer + offloadersDirectory: + type: string + s3ManagedLedgerOffloadBucket: + type: string + s3ManagedLedgerOffloadCredentialId: + type: string + s3ManagedLedgerOffloadCredentialSecret: + type: string + s3ManagedLedgerOffloadRegion: + type: string + s3ManagedLedgerOffloadRole: + type: string + s3ManagedLedgerOffloadRoleSessionName: + type: string + s3ManagedLedgerOffloadServiceEndpoint: + type: string + type: object partitions: default: 0 description: |- @@ -190,12 +329,70 @@ spec: Set to 0 for a non-partitioned topic. format: int32 type: integer + persistencePolicies: + description: |- + PersistencePolicies defines the persistence configuration for the topic. + This controls how data is stored and replicated in BookKeeper. + properties: + bookkeeperAckQuorum: + description: |- + BookkeeperAckQuorum specifies the number of replicas to wait for acknowledgment + Must be <= BookkeeperWriteQuorum + format: int32 + minimum: 1 + type: integer + bookkeeperEnsemble: + description: |- + BookkeeperEnsemble specifies the number of bookies to use for a ledger + This determines the replication factor for storing data + format: int32 + minimum: 1 + type: integer + bookkeeperWriteQuorum: + description: |- + BookkeeperWriteQuorum specifies the number of replicas to write for each entry + Must be <= BookkeeperEnsemble + format: int32 + minimum: 1 + type: integer + managedLedgerMaxMarkDeleteRate: + description: |- + ManagedLedgerMaxMarkDeleteRate specifies the maximum rate at which mark-delete operations can be performed + This helps control the rate of acknowledgment processing + Value should be a decimal number as string (e.g., "1.5", "2.0") + type: string + type: object persistent: default: true description: |- Persistent determines if the topic is persistent (true) or non-persistent (false). Defaults to true if not specified. type: boolean + properties: + additionalProperties: + type: string + description: |- + Properties is a map of user-defined properties associated with the topic. + These can be used to store additional metadata about the topic. + type: object + publishRate: + description: |- + PublishRate defines the message publish rate limiting policy for the topic. + This controls the rate at which producers can publish messages. + properties: + publishThrottlingRateInByte: + description: |- + PublishThrottlingRateInByte specifies the maximum number of bytes per second that producers can publish + -1 means unlimited + format: int64 + type: integer + publishThrottlingRateInMsg: + description: |- + PublishThrottlingRateInMsg specifies the maximum number of messages per second that producers can publish + -1 means unlimited + format: int32 + type: integer + type: object replicationClusters: description: |- ReplicationClusters is the list of clusters to which the topic is replicated @@ -205,6 +402,31 @@ spec: items: type: string type: array + replicatorDispatchRate: + description: |- + ReplicatorDispatchRate defines the message dispatch rate limiting policy for replicators. + This controls the rate at which messages are replicated to other clusters. + properties: + dispatchThrottlingRateInByte: + description: |- + DispatchThrottlingRateInByte specifies the maximum number of bytes per second allowed + -1 means unlimited + format: int64 + type: integer + dispatchThrottlingRateInMsg: + description: |- + DispatchThrottlingRateInMsg specifies the maximum number of messages per second allowed + -1 means unlimited + format: int32 + type: integer + ratePeriodInSecond: + default: 1 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + type: object retentionSize: anyOf: - type: integer @@ -212,14 +434,33 @@ spec: description: |- RetentionSize specifies the maximum size of backlog retained on the topic. Should be set in conjunction with RetentionTime for effective retention policy. - Retention Quota must exceed configured backlog quota for topic + Retention Quota must exceed configured backlog quota for topic. + Use "-1" for infinite retention size. + Valid formats: "1Gi", "500Mi", "100M", "-1" pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ x-kubernetes-int-or-string: true retentionTime: description: |- RetentionTime specifies the minimum time to retain messages on the topic. Should be set in conjunction with RetentionSize for effective retention policy. - Retention Quota must exceed configured backlog quota for topic + Retention Quota must exceed configured backlog quota for topic. + Use "-1" for infinite retention time. + Valid formats: "1h", "30m", "5s", "-1" + type: string + schemaCompatibilityStrategy: + description: |- + SchemaCompatibilityStrategy defines the schema compatibility strategy for the topic. + This controls how schema evolution is handled. + enum: + - UNDEFINED + - ALWAYS_INCOMPATIBLE + - ALWAYS_COMPATIBLE + - BACKWARD + - FORWARD + - FULL + - BACKWARD_TRANSITIVE + - FORWARD_TRANSITIVE + - FULL_TRANSITIVE type: string schemaInfo: description: SchemaInfo defines the schema for the topic, if any. @@ -246,6 +487,55 @@ spec: are one of the other schema types. type: string type: object + schemaValidationEnforced: + description: |- + SchemaValidationEnforced determines whether schema validation is enforced for the topic. + When enabled, only messages that conform to the topic's schema will be accepted. + type: boolean + subscribeRate: + description: |- + SubscribeRate defines the subscription rate limiting policy for the topic. + This controls the rate at which new subscriptions can be created. + properties: + ratePeriodInSecond: + default: 30 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + subscribeThrottlingRatePerConsumer: + description: |- + SubscribeThrottlingRatePerConsumer specifies the maximum subscribe rate per consumer + -1 means unlimited + format: int32 + type: integer + type: object + subscriptionDispatchRate: + description: |- + SubscriptionDispatchRate defines the message dispatch rate limiting policy for subscriptions. + This controls the rate at which messages are delivered to consumers per subscription. + properties: + dispatchThrottlingRateInByte: + description: |- + DispatchThrottlingRateInByte specifies the maximum number of bytes per second allowed + -1 means unlimited + format: int64 + type: integer + dispatchThrottlingRateInMsg: + description: |- + DispatchThrottlingRateInMsg specifies the maximum number of messages per second allowed + -1 means unlimited + format: int32 + type: integer + ratePeriodInSecond: + default: 1 + description: RatePeriodInSecond specifies the time window in seconds + for rate calculation + format: int32 + minimum: 1 + type: integer + type: object required: - connectionRef - name diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_rolebindings.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_rolebindings.yaml new file mode 100644 index 00000000..df7e4042 --- /dev/null +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_rolebindings.yaml @@ -0,0 +1,255 @@ +# Copyright 2025 StreamNative +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: rolebindings.resource.streamnative.io +spec: + group: resource.streamnative.io + names: + categories: + - streamnative + - all + kind: RoleBinding + listKind: RoleBindingList + plural: rolebindings + singular: rolebinding + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: READY + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: RoleBinding is the Schema for the RoleBindings 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: RoleBindingSpec defines the desired state of RoleBinding + properties: + apiServerRef: + description: APIServerRef is the reference to the StreamNativeCloudConnection + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + type: object + x-kubernetes-map-type: atomic + cel: + description: CEL is an optional CEL expression for the role binding + type: string + clusterRole: + description: ClusterRole is the reference to the role that will be + granted + type: string + identityPools: + description: IdentityPools is a list of IdentityPools that will be + granted the role + items: + type: string + type: array + serviceAccounts: + description: ServiceAccounts is a list of ServiceAccounts that will + be granted the role + items: + type: string + type: array + srnCluster: + description: SRNCluster is the cluster of the SRN + items: + type: string + type: array + srnInstance: + description: SRNInstance is the pulsar instance of the SRN + items: + type: string + type: array + srnNamespace: + description: SRNNamespace is the namespace of the SRN + items: + type: string + type: array + srnOrganization: + description: SRNOrganization is the organization of the SRN + items: + type: string + type: array + srnSecret: + description: SRNSecret is the secret of the SRN + items: + type: string + type: array + srnServiceAccount: + description: SRNServiceAccount is the service account of the SRN + items: + type: string + type: array + srnSubscription: + description: SRNSubscription is the subscription of the SRN + items: + type: string + type: array + srnTenant: + description: SRNTenant is the tenant of the SRN + items: + type: string + type: array + srnTopicDomain: + description: SRNTopicDomain is the topic domain of the SRN + items: + type: string + type: array + srnTopicName: + description: SRNTopicName is the topic of the SRN + items: + type: string + type: array + users: + description: Users is a list of Users that will be granted the role + items: + type: string + type: array + required: + - apiServerRef + - clusterRole + type: object + status: + description: RoleBindingStatus defines the observed state of RoleBinding + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + failedClusters: + description: FailedClusters is a list of clusters where the role binding + failed + items: + type: string + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation + format: int64 + type: integer + syncedClusters: + additionalProperties: + type: string + description: SyncedClusters is a map of clusters where the role binding + is synced + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccountbindings.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccountbindings.yaml new file mode 100644 index 00000000..b6b52f41 --- /dev/null +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccountbindings.yaml @@ -0,0 +1,193 @@ +# Copyright 2025 StreamNative +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: serviceaccountbindings.resource.streamnative.io +spec: + group: resource.streamnative.io + names: + categories: + - streamnative + - all + kind: ServiceAccountBinding + listKind: ServiceAccountBindingList + plural: serviceaccountbindings + singular: serviceaccountbinding + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: READY + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ServiceAccountBinding is the Schema for the ServiceAccountBindings + 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: ServiceAccountBindingSpec defines the desired state of ServiceAccountBinding + properties: + apiServerRef: + description: |- + APIServerRef is the reference to the StreamNativeCloudConnection + If not provided, it will be retrieved from the referenced ServiceAccount + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + type: object + x-kubernetes-map-type: atomic + poolMemberRefs: + description: PoolMemberRefs refers to a list of PoolMembers in the + current namespace or other namespaces + items: + description: PoolMemberReference is a reference to a pool member + with a given name. + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + type: array + serviceAccountName: + description: ServiceAccountName refers to the ServiceAccount under + the same namespace as this binding object + type: string + required: + - poolMemberRefs + - serviceAccountName + type: object + status: + description: ServiceAccountBindingStatus defines the observed state of + ServiceAccountBinding + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation + format: int64 + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccounts.yaml b/charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccounts.yaml new file mode 100644 index 00000000..c31df86e --- /dev/null +++ b/charts/pulsar-resources-operator/crds/resource.streamnative.io_serviceaccounts.yaml @@ -0,0 +1,175 @@ +# Copyright 2025 StreamNative +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + name: serviceaccounts.resource.streamnative.io +spec: + group: resource.streamnative.io + names: + categories: + - streamnative + - all + kind: ServiceAccount + listKind: ServiceAccountList + plural: serviceaccounts + singular: serviceaccount + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: AGE + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: READY + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ServiceAccount is the Schema for the ServiceAccounts 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: ServiceAccountSpec defines the desired state of ServiceAccount + properties: + apiServerRef: + description: APIServerRef is the reference to the StreamNativeCloudConnection + properties: + name: + default: "" + description: |- + Name of the referent. + This field is effectively required, but due to backwards compatibility is + allowed to be empty. Instances of this type with an empty value here are + almost certainly wrong. + TODO: Add other useful fields. apiVersion, kind, uid? + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + type: string + type: object + x-kubernetes-map-type: atomic + required: + - apiServerRef + type: object + status: + description: ServiceAccountStatus defines the observed state of ServiceAccount + properties: + conditions: + description: Conditions represent the latest available observations + of an object's state + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + observedGeneration: + description: ObservedGeneration is the last observed generation + format: int64 + type: integer + privateKeyData: + description: PrivateKeyData provides the private key data (in base-64 + format) for authentication purposes + type: string + privateKeyType: + description: PrivateKeyType indicates the type of private key information + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/pulsar-resources-operator/templates/role.yaml b/charts/pulsar-resources-operator/templates/role.yaml index 9e55a72a..5fc656b0 100644 --- a/charts/pulsar-resources-operator/templates/role.yaml +++ b/charts/pulsar-resources-operator/templates/role.yaml @@ -430,3 +430,107 @@ rules: - get - patch - update +- apiGroups: + - resource.streamnative.io + resources: + - apikeys + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - resource.streamnative.io + resources: + - apikeys/finalizers + verbs: + - update +- apiGroups: + - resource.streamnative.io + resources: + - apikeys/status + verbs: + - get + - patch + - update +- apiGroups: + - resource.streamnative.io + resources: + - serviceaccounts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - resource.streamnative.io + resources: + - serviceaccounts/finalizers + verbs: + - update +- apiGroups: + - resource.streamnative.io + resources: + - serviceaccounts/status + verbs: + - get + - patch + - update +- apiGroups: + - resource.streamnative.io + resources: + - serviceaccountbindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - resource.streamnative.io + resources: + - serviceaccountbindings/finalizers + verbs: + - update +- apiGroups: + - resource.streamnative.io + resources: + - serviceaccountbindings/status + verbs: + - get + - patch + - update +- apiGroups: + - resource.streamnative.io + resources: + - rolebindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - resource.streamnative.io + resources: + - rolebindings/finalizers + verbs: + - update +- apiGroups: + - resource.streamnative.io + resources: + - rolebindings/status + verbs: + - get + - patch + - update From 4eacbc5142deb4a2fe48c7a6cefcfffaa920575f Mon Sep 17 00:00:00 2001 From: Rui Fu Date: Mon, 8 Sep 2025 15:49:44 +0800 Subject: [PATCH 2/7] release: bump version to v0.14.0-rc.1 --- charts/pulsar-resources-operator/Chart.yaml | 4 ++-- charts/pulsar-resources-operator/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/pulsar-resources-operator/Chart.yaml b/charts/pulsar-resources-operator/Chart.yaml index c976a835..782c6400 100644 --- a/charts/pulsar-resources-operator/Chart.yaml +++ b/charts/pulsar-resources-operator/Chart.yaml @@ -30,13 +30,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.9.2 +version: v0.14.0-rc.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.9.2" +appVersion: "v0.14.0-rc.1" # This is a semver range of compatible Kubernetes versions. Helm will validate the version # constraints when installing the chart and fail if the cluster runs an unsupported Kubernetes version diff --git a/charts/pulsar-resources-operator/README.md b/charts/pulsar-resources-operator/README.md index 913f3582..4eda7a5a 100644 --- a/charts/pulsar-resources-operator/README.md +++ b/charts/pulsar-resources-operator/README.md @@ -1,6 +1,6 @@ # Pulsar Resources Operator -![Version: v0.9.1](https://img.shields.io/badge/Version-v0.9.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.9.1](https://img.shields.io/badge/AppVersion-v0.9.1-informational?style=flat-square) +![Version: v0.14.0](https://img.shields.io/badge/Version-v0.14.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.14.0](https://img.shields.io/badge/AppVersion-v0.14.0-informational?style=flat-square) ## Installing the Chart From 39dcab4167e22f30f5169548f41e266d0ae2bcd5 Mon Sep 17 00:00:00 2001 From: Rui Fu Date: Tue, 9 Sep 2025 21:48:47 +0800 Subject: [PATCH 3/7] chore: regenerate helm values schema json (#342) * regenerate helm json * fix helm charts --- .../values.schema.json | 646 ++++-------------- 1 file changed, 151 insertions(+), 495 deletions(-) diff --git a/charts/pulsar-resources-operator/values.schema.json b/charts/pulsar-resources-operator/values.schema.json index e1197dff..361b7dbe 100644 --- a/charts/pulsar-resources-operator/values.schema.json +++ b/charts/pulsar-resources-operator/values.schema.json @@ -1,551 +1,207 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://streamnative.io/pulsar-resources-operator-schema.json", "type": "object", - "title": "The root schema", - "description": "The root schema comprises the entire JSON document.", - "required": [ - "replicaCount", - "image", - "imagePullSecrets", - "resources" - ], "properties": { - "namespace": { - "$id": "#/properties/namespace", - "type": "string", - "title": "The namespace schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "" - ] - }, - "replicaCount": { - "$id": "#/properties/replicaCount", - "type": "integer", - "title": "The replicaCount schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - 1 - ] - }, - "image": { - "$id": "#/properties/image", - "type": "object", - "title": "The image schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - { - "pullPolicy": "IfNotPresent" - } - ], - "properties": { - "pullPolicy": { - "$id": "#/properties/image/properties/pullPolicy", - "type": "string", - "title": "The pullPolicy schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "IfNotPresent" - ] - }, - "manager": { - "$id": "#/properties/image/properties/manager", - "type": "object", - "title": "The operator image schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - { - "registry": "dockerio", - "repository": "streamnative/pulsar-resources-operator", - "tag": "" - } - ], - "required": [ - "registry", - "repository" - ], - "properties": { - "registry": { - "$id": "#/properties/image/properties/manager/properties/registry", - "type": "string", - "title": "The registry schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "docker.io" - ] - }, - "repository": { - "$id": "#/properties/image/properties/manager/properties/repository", - "type": "string", - "title": "The repository schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "streamnative/pulsar-resources-operator" - ] - }, - "tag": { - "$id": "#/properties/image/properties/manager/properties/tag", - "type": "string", - "title": "The tag schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "" - ] - } - } - }, - "kubeRbacProxy": { - "type": "object", - "default": {}, - "title": "The kubeRbacProxy Schema", - "required": [ - "registry", - "repository", - "tag" - ], - "properties": { - "registry": { - "type": "string", - "default": "", - "title": "The registry Schema", - "examples": [ - "gcr.io" - ] - }, - "repository": { - "type": "string", - "default": "", - "title": "The repository Schema", - "examples": [ - "kubebuilder/kube-rbac-proxy" - ] - }, - "tag": { - "type": "string", - "default": "", - "title": "The tag Schema", - "examples": [ - "v0.14.4" - ] - } - }, - "examples": [ - { - "registry": "gcr.io", - "repository": "kubebuilder/kube-rbac-proxy", - "tag": "v0.14.4" - } - ] - } - }, - "additionalProperties": true - }, - "imagePullSecrets": { - "$id": "#/properties/imagePullSecrets", - "type": "array", - "title": "The imagePullSecrets schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - [] - ], - "additionalItems": true, - "items": { - "$id": "#/properties/imagePullSecrets/items", - "anyOf": [ - { - "$id": "#/properties/imagePullSecrets/items/anyOf/0", - "type": "object", - "title": "The first anyOf schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - { - "name": "test" - } - ], - "required": [ - "name" - ], - "properties": { - "name": { - "$id": "#/properties/imagePullSecrets/items/anyOf/0/properties/name", - "type": "string", - "title": "The name schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "test" - ] - } - }, - "additionalProperties": true - } - ] - } - }, - "nameOverride": { - "$id": "#/properties/nameOverride", - "type": "string", - "title": "The nameOverride schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "" - ] - }, - "fullnameOverride": { - "$id": "#/properties/fullnameOverride", - "type": "string", - "title": "The fullnameOverride schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "" - ] - }, - "serviceAccount": { - "$id": "#/properties/serviceAccount", - "type": "object", - "title": "The serviceAccount schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - { - "create": true, - "annotations": {}, - "name": "" - } - ], - "required": [ - "create", - "annotations", - "name" - ], - "properties": { - "create": { - "$id": "#/properties/serviceAccount/properties/create", - "type": "boolean", - "title": "The create schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - true - ] - }, - "annotations": { - "$id": "#/properties/serviceAccount/properties/annotations", - "type": "object", - "title": "The annotations schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "name": { - "$id": "#/properties/serviceAccount/properties/name", - "type": "string", - "title": "The name schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "" - ] - } - }, - "additionalProperties": true - }, - "labels": { - "$id": "#/properties/labels", - "type": "object", - "title": "The labels schema", - "description": "customized labels for deployment", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "podAnnotations": { - "$id": "#/properties/podAnnotations", - "type": "object", - "title": "The podAnnotations schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "podLabels": { - "$id": "#/properties/podLabels", - "type": "object", - "title": "The labels schema", - "description": "customized labels for pod", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "podSecurityContext": { - "$id": "#/properties/podSecurityContext", - "type": "object", - "title": "The podSecurityContext schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "securityContext": { - "$id": "#/properties/securityContext", - "type": "object", - "title": "The securityContext schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "resources": { - "$id": "#/properties/resources", - "type": "object", - "title": "The resources schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - {} - ], - "required": [], - "properties": { - "requests": { - "$id": "#/properties/resources/properties/requests", - "type": "object", - "title": "The requests schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - { - "cpu": "100m", - "memory": "128Mi" - } - ], - "required": [ - "cpu", - "memory" - ], - "properties": { - "cpu": { - "$id": "#/properties/resources/properties/requests/properties/cpu", - "type": "string", - "title": "The cpu schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "100m" - ] - }, - "memory": { - "$id": "#/properties/resources/properties/requests/properties/memory", - "type": "string", - "title": "The memory schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - "128Mi" - ] - } - }, - "additionalProperties": true - } - }, - "additionalProperties": true - }, - "nodeSelector": { - "$id": "#/properties/nodeSelector", - "type": "object", - "title": "The nodeSelector schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "tolerations": { - "$id": "#/properties/tolerations", - "type": "array", - "title": "The tolerations schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - [] - ], - "additionalItems": true, - "items": { - "$id": "#/properties/tolerations/items" - } - }, "affinity": { - "$id": "#/properties/affinity", - "type": "object", - "title": "The affinity schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - {} - ], - "required": [], - "additionalProperties": true - }, - "terminationGracePeriodSeconds": { - "$id": "#/properties/terminationGracePeriodSeconds", - "type": "integer", - "title": "The terminationGracePeriodSeconds schema", - "description": "An explanation about the purpose of this instance.", - "examples": [ - 10 - ] + "type": "object" }, "cloudStorage": { "type": "object", - "description": "Cloud storage providers configuration", "properties": { - "s3": { + "azure": { "type": "object", - "description": "AWS S3 configuration", "properties": { - "enabled": { - "type": "boolean", - "description": "Enable AWS S3 support" - }, - "region": { - "type": "string", - "description": "AWS region" + "accountName": { + "type": "string" }, "credentials": { "type": "object", - "description": "AWS credentials secret configuration", "properties": { + "accountKey": { + "type": "string" + }, "create": { - "type": "boolean", - "description": "Create a new secret for AWS credentials" + "type": "boolean" }, - "secretName": { - "type": "string", - "description": "Existing secret name" + "sasToken": { + "type": "string" }, - "accessKeyId": { - "type": "string", - "description": "AWS access key ID (only used if create is true)" + "secretName": { + "type": "string" }, - "secretAccessKey": { - "type": "string", - "description": "AWS secret access key (only used if create is true)" + "useAccountKey": { + "type": "boolean" } - }, - "required": [ - "secretName" - ] + } + }, + "enabled": { + "type": "boolean" } - }, - "required": [ - "enabled" - ] + } }, "gcs": { "type": "object", - "description": "Google Cloud Storage configuration", "properties": { "enabled": { - "type": "boolean", - "description": "Enable Google Cloud Storage support" + "type": "boolean" }, "serviceAccount": { "type": "object", - "description": "Service account configuration", "properties": { - "useWorkloadIdentity": { - "type": "boolean", - "description": "Use workload identity" - }, - "name": { - "type": "string", - "description": "Name of the Kubernetes service account for workload identity" - }, "key": { "type": "object", - "description": "Service account key configuration", "properties": { "create": { - "type": "boolean", - "description": "Create a new secret for service account key" - }, - "secretName": { - "type": "string", - "description": "Existing secret name" + "type": "boolean" }, "json": { - "type": "string", - "description": "Service account key JSON content (only used if create is true)" + "type": "string" }, "mountPath": { - "type": "string", - "description": "Mount path of the service account key file" + "type": "string" + }, + "secretName": { + "type": "string" } - }, - "required": [ - "secretName", - "mountPath" - ] + } + }, + "name": { + "type": "string" + }, + "useWorkloadIdentity": { + "type": "boolean" } } } - }, - "required": [ - "enabled" - ] + } }, - "azure": { + "s3": { "type": "object", - "description": "Azure Blob Storage configuration", "properties": { - "enabled": { - "type": "boolean", - "description": "Enable Azure Blob Storage support" - }, - "accountName": { - "type": "string", - "description": "Azure storage account name" - }, "credentials": { "type": "object", - "description": "Azure credentials configuration", "properties": { - "create": { - "type": "boolean", - "description": "Create a new secret for Azure credentials" - }, - "secretName": { - "type": "string", - "description": "Existing secret name" + "accessKeyId": { + "type": "string" }, - "accountKey": { - "type": "string", - "description": "Storage account key (only used if create is true)" + "create": { + "type": "boolean" }, - "sasToken": { - "type": "string", - "description": "SAS token (only used if create is true)" + "secretAccessKey": { + "type": "string" }, - "useAccountKey": { - "type": "boolean", - "description": "Use account key for authentication (if false, will use SAS token)" + "secretName": { + "type": "string" } - }, - "required": [ - "secretName" - ] + } + }, + "enabled": { + "type": "boolean" + }, + "region": { + "type": "string" + } + } + } + } + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "features": { + "type": "object", + "properties": { + "alwaysUpdatePulsarResource": { + "type": "boolean" + }, + "resyncPeriod": { + "type": "integer" + }, + "retryCount": { + "type": "integer" + } + } + }, + "fullnameOverride": { + "type": "string" + }, + "image": { + "type": "object", + "properties": { + "manager": { + "type": "object", + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" } - }, - "required": [ - "enabled" - ] + } + }, + "pullPolicy": { + "type": "string" + } + } + }, + "imagePullSecrets": { + "type": "array" + }, + "labels": { + "type": "object" + }, + "nameOverride": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "nodeSelector": { + "type": "object" + }, + "podAnnotations": { + "type": "object" + }, + "podLabels": { + "type": "object" + }, + "podSecurityContext": { + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "resources": { + "type": "object" + }, + "securityContext": { + "type": "object" + }, + "serviceAccount": { + "type": "object", + "properties": { + "annotations": { + "type": "object" + }, + "create": { + "type": "boolean" + }, + "name": { + "type": "string" } } + }, + "terminationGracePeriodSeconds": { + "type": "integer" + }, + "tolerations": { + "type": "array" } - }, - "additionalProperties": true -} \ No newline at end of file + } +} From 881635151b4e1b4678a4b725d3b00a8b088fb133 Mon Sep 17 00:00:00 2001 From: Rui Fu Date: Tue, 9 Sep 2025 21:49:59 +0800 Subject: [PATCH 4/7] release: bump version to v0.14.0-rc.2 --- charts/pulsar-resources-operator/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/pulsar-resources-operator/Chart.yaml b/charts/pulsar-resources-operator/Chart.yaml index 782c6400..68402ac9 100644 --- a/charts/pulsar-resources-operator/Chart.yaml +++ b/charts/pulsar-resources-operator/Chart.yaml @@ -30,13 +30,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.14.0-rc.1 +version: v0.14.0-rc.2 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.14.0-rc.1" +appVersion: "v0.14.0-rc.2" # This is a semver range of compatible Kubernetes versions. Helm will validate the version # constraints when installing the chart and fail if the cluster runs an unsupported Kubernetes version From 93439a22263e64dbf7a4692e02a260fd48fcfbdc Mon Sep 17 00:00:00 2001 From: Rui Fu Date: Wed, 10 Sep 2025 10:31:56 +0800 Subject: [PATCH 5/7] fix: Use pointer types for boolean fields in PulsarFunction to prevent omitempty issues (#343) * fix: Use pointer types for boolean fields in PulsarFunction to prevent omitempty issues * fix ci --- api/v1alpha1/pulsarfunction_types.go | 14 ++-- api/v1alpha1/zz_generated.deepcopy.go | 35 ++++++++ docs/pulsar_sink.md | 2 +- pkg/admin/impl.go | 113 ++++++++++++++++---------- tests/utils/spec.go | 15 ++-- 5 files changed, 119 insertions(+), 60 deletions(-) diff --git a/api/v1alpha1/pulsarfunction_types.go b/api/v1alpha1/pulsarfunction_types.go index 964d4889..b5027d67 100644 --- a/api/v1alpha1/pulsarfunction_types.go +++ b/api/v1alpha1/pulsarfunction_types.go @@ -38,15 +38,15 @@ type PulsarFunctionSpec struct { // CleanupSubscription is the flag to indicate whether the subscription should be cleaned up when the function is deleted // +optional - CleanupSubscription bool `json:"cleanupSubscription"` + CleanupSubscription *bool `json:"cleanupSubscription,omitempty"` // RetainOrdering is the flag to indicate whether the function should retain ordering // +optional - RetainOrdering bool `json:"retainOrdering"` + RetainOrdering *bool `json:"retainOrdering,omitempty"` // RetainKeyOrdering is the flag to indicate whether the function should retain key ordering // +optional - RetainKeyOrdering bool `json:"retainKeyOrdering"` + RetainKeyOrdering *bool `json:"retainKeyOrdering,omitempty"` // BatchBuilder is the batch builder that the function uses // +optional @@ -54,11 +54,11 @@ type PulsarFunctionSpec struct { // ForwardSourceMessageProperty is the flag to indicate whether the function should forward source message properties // +optional - ForwardSourceMessageProperty bool `json:"forwardSourceMessageProperty"` + ForwardSourceMessageProperty *bool `json:"forwardSourceMessageProperty,omitempty"` // AutoAck is the flag to indicate whether the function should auto ack // +optional - AutoAck bool `json:"autoAck"` + AutoAck *bool `json:"autoAck,omitempty"` // Parallelism is the parallelism of the function // +optional @@ -186,11 +186,11 @@ type PulsarFunctionSpec struct { // ExposePulsarAdminClientEnabled is the flag to indicate whether the function should expose pulsar admin client // +optional - ExposePulsarAdminClientEnabled bool `json:"exposePulsarAdminClientEnabled"` + ExposePulsarAdminClientEnabled *bool `json:"exposePulsarAdminClientEnabled,omitempty"` // SkipToLatest is the flag to indicate whether the function should skip to latest // +optional - SkipToLatest bool `json:"skipToLatest"` + SkipToLatest *bool `json:"skipToLatest,omitempty"` // SubscriptionPosition is the subscription position of the function // +optional diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 1dda32cc..74fc5e17 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1568,11 +1568,36 @@ func (in *PulsarFunctionSpec) DeepCopyInto(out *PulsarFunctionSpec) { *out = new(string) **out = **in } + if in.CleanupSubscription != nil { + in, out := &in.CleanupSubscription, &out.CleanupSubscription + *out = new(bool) + **out = **in + } + if in.RetainOrdering != nil { + in, out := &in.RetainOrdering, &out.RetainOrdering + *out = new(bool) + **out = **in + } + if in.RetainKeyOrdering != nil { + in, out := &in.RetainKeyOrdering, &out.RetainKeyOrdering + *out = new(bool) + **out = **in + } if in.BatchBuilder != nil { in, out := &in.BatchBuilder, &out.BatchBuilder *out = new(string) **out = **in } + if in.ForwardSourceMessageProperty != nil { + in, out := &in.ForwardSourceMessageProperty, &out.ForwardSourceMessageProperty + *out = new(bool) + **out = **in + } + if in.AutoAck != nil { + in, out := &in.AutoAck, &out.AutoAck + *out = new(bool) + **out = **in + } if in.MaxMessageRetries != nil { in, out := &in.MaxMessageRetries, &out.MaxMessageRetries *out = new(int) @@ -1658,6 +1683,16 @@ func (in *PulsarFunctionSpec) DeepCopyInto(out *PulsarFunctionSpec) { (*out)[key] = val } } + if in.ExposePulsarAdminClientEnabled != nil { + in, out := &in.ExposePulsarAdminClientEnabled, &out.ExposePulsarAdminClientEnabled + *out = new(bool) + **out = **in + } + if in.SkipToLatest != nil { + in, out := &in.SkipToLatest, &out.SkipToLatest + *out = new(bool) + **out = **in + } out.ConnectionRef = in.ConnectionRef } diff --git a/docs/pulsar_sink.md b/docs/pulsar_sink.md index a5d816aa..c22a8230 100644 --- a/docs/pulsar_sink.md +++ b/docs/pulsar_sink.md @@ -41,7 +41,7 @@ This table lists specifications available for the `PulsarSink` resource. | `topicsPattern` | The topic pattern. | Optional | | `resources` | The resources of the sink. | Optional | | `timeoutMs` | The timeout in milliseconds. | Optional | -| `cleanupSubscription` | The cleanup subscription (defaults to false when omitted). | Optional | +| `cleanupSubscription` | The cleanup subscription. | Optional | | `retainOrdering` | The retain ordering. | Optional | | `retainKeyOrdering` | The retain key ordering. | Optional | | `autoAck` | The auto ack. | Optional | diff --git a/pkg/admin/impl.go b/pkg/admin/impl.go index 331efdc5..3af09d55 100644 --- a/pkg/admin/impl.go +++ b/pkg/admin/impl.go @@ -46,14 +46,6 @@ const ( TopicDomainNonPersistent = "non-persistent" ) -// ptrBoolToBool converts a pointer to bool to bool with default value false -func ptrBoolToBool(b *bool) bool { - if b == nil { - return false - } - return *b -} - // Type conversion functions for external library types // convertOffloadPolicies converts our local OffloadPolicies to the external library type @@ -1281,37 +1273,58 @@ func (p *PulsarAdminClient) DeletePulsarFunction(tenant, namespace, name string) // ApplyPulsarFunction creates or updates a pulsar function func (p *PulsarAdminClient) ApplyPulsarFunction(tenant, namespace, name, packageURL string, param *v1alpha1.PulsarFunctionSpec, changed bool) error { functionConfig := utils.FunctionConfig{ - Tenant: tenant, - Namespace: namespace, - Name: name, - ClassName: param.ClassName, - Inputs: param.Inputs, - Parallelism: param.Parallelism, - TimeoutMs: param.TimeoutMs, - TopicsPattern: param.TopicsPattern, - CleanupSubscription: param.CleanupSubscription, - RetainOrdering: param.RetainOrdering, - RetainKeyOrdering: param.RetainKeyOrdering, - ForwardSourceMessageProperty: param.ForwardSourceMessageProperty, - AutoAck: param.AutoAck, - MaxMessageRetries: param.MaxMessageRetries, - CustomSerdeInputs: param.CustomSerdeInputs, - CustomSchemaInputs: param.CustomSchemaInputs, - InputTypeClassName: param.InputTypeClassName, - Output: param.Output, - OutputSerdeClassName: param.OutputSerdeClassName, - OutputSchemaType: param.OutputSchemaType, - OutputTypeClassName: param.OutputTypeClassName, - CustomSchemaOutputs: param.CustomSchemaOutputs, - LogTopic: param.LogTopic, - ProcessingGuarantees: param.ProcessingGuarantees, - DeadLetterTopic: param.DeadLetterTopic, - SubName: param.SubName, - RuntimeFlags: param.RuntimeFlags, - MaxPendingAsyncRequests: param.MaxPendingAsyncRequests, - ExposePulsarAdminClientEnabled: param.ExposePulsarAdminClientEnabled, - SkipToLatest: param.SkipToLatest, - SubscriptionPosition: param.SubscriptionPosition, + Tenant: tenant, + Namespace: namespace, + Name: name, + ClassName: param.ClassName, + Inputs: param.Inputs, + Parallelism: param.Parallelism, + TimeoutMs: param.TimeoutMs, + TopicsPattern: param.TopicsPattern, + MaxMessageRetries: param.MaxMessageRetries, + CustomSerdeInputs: param.CustomSerdeInputs, + CustomSchemaInputs: param.CustomSchemaInputs, + InputTypeClassName: param.InputTypeClassName, + Output: param.Output, + OutputSerdeClassName: param.OutputSerdeClassName, + OutputSchemaType: param.OutputSchemaType, + OutputTypeClassName: param.OutputTypeClassName, + CustomSchemaOutputs: param.CustomSchemaOutputs, + LogTopic: param.LogTopic, + ProcessingGuarantees: param.ProcessingGuarantees, + DeadLetterTopic: param.DeadLetterTopic, + SubName: param.SubName, + RuntimeFlags: param.RuntimeFlags, + MaxPendingAsyncRequests: param.MaxPendingAsyncRequests, + SubscriptionPosition: param.SubscriptionPosition, + } + + if param.CleanupSubscription != nil { + functionConfig.CleanupSubscription = *param.CleanupSubscription + } + + if param.RetainOrdering != nil { + functionConfig.RetainOrdering = *param.RetainOrdering + } + + if param.RetainKeyOrdering != nil { + functionConfig.RetainKeyOrdering = *param.RetainKeyOrdering + } + + if param.ForwardSourceMessageProperty != nil { + functionConfig.ForwardSourceMessageProperty = *param.ForwardSourceMessageProperty + } + + if param.AutoAck != nil { + functionConfig.AutoAck = *param.AutoAck + } + + if param.ExposePulsarAdminClientEnabled != nil { + functionConfig.ExposePulsarAdminClientEnabled = *param.ExposePulsarAdminClientEnabled + } + + if param.SkipToLatest != nil { + functionConfig.SkipToLatest = *param.SkipToLatest } if param.BatchBuilder != nil { @@ -1460,11 +1473,7 @@ func (p *PulsarAdminClient) ApplyPulsarSink(tenant, namespace, name, packageURL TopicsPattern: param.TopicsPattern, TimeoutMs: param.TimeoutMs, - CleanupSubscription: ptrBoolToBool(param.CleanupSubscription), - RetainOrdering: ptrBoolToBool(param.RetainOrdering), - RetainKeyOrdering: ptrBoolToBool(param.RetainKeyOrdering), - AutoAck: ptrBoolToBool(param.AutoAck), - Parallelism: param.Parallelism, + Parallelism: param.Parallelism, SinkType: param.SinkType, Archive: packageURL, @@ -1487,6 +1496,22 @@ func (p *PulsarAdminClient) ApplyPulsarSink(tenant, namespace, name, packageURL TransformFunctionConfig: param.TransformFunctionConfig, } + if param.CleanupSubscription != nil { + sinkConfig.CleanupSubscription = *param.CleanupSubscription + } + + if param.RetainOrdering != nil { + sinkConfig.RetainOrdering = *param.RetainOrdering + } + + if param.RetainKeyOrdering != nil { + sinkConfig.RetainKeyOrdering = *param.RetainKeyOrdering + } + + if param.AutoAck != nil { + sinkConfig.AutoAck = *param.AutoAck + } + if param.Resources != nil { s, err := strconv.ParseFloat(param.Resources.CPU, 64) if err != nil { diff --git a/tests/utils/spec.go b/tests/utils/spec.go index ac6a3b84..5f60157f 100644 --- a/tests/utils/spec.go +++ b/tests/utils/spec.go @@ -22,7 +22,6 @@ import ( v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/pointer" "k8s.io/utils/ptr" "github.com/streamnative/pulsar-resources-operator/api/v1alpha1" @@ -513,15 +512,15 @@ func MakePulsarFunction(namespace, name, functionPackageUrl, connectionName stri ClassName: "org.apache.pulsar.functions.api.examples.ExclamationFunction", SubName: "test-sub", SubscriptionPosition: "Latest", - CleanupSubscription: true, - SkipToLatest: true, - ForwardSourceMessageProperty: true, - RetainKeyOrdering: true, - AutoAck: true, - MaxMessageRetries: pointer.Int(101), + CleanupSubscription: ptr.To(true), + SkipToLatest: ptr.To(true), + ForwardSourceMessageProperty: ptr.To(true), + RetainKeyOrdering: ptr.To(true), + AutoAck: ptr.To(true), + MaxMessageRetries: ptr.To(101), DeadLetterTopic: "dl-topic", LogTopic: "func-log", - TimeoutMs: pointer.Int64(6666), + TimeoutMs: ptr.To[int64](6666), Secrets: map[string]v1alpha1.FunctionSecretKeyRef{ "SECRET1": { "sectest", "hello", From 8446099847dbef2a86e9082caabf3128bd3441f8 Mon Sep 17 00:00:00 2001 From: Rui Fu Date: Wed, 10 Sep 2025 10:33:16 +0800 Subject: [PATCH 6/7] release: bump version to v0.14.0-rc.3 --- charts/pulsar-resources-operator/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/pulsar-resources-operator/Chart.yaml b/charts/pulsar-resources-operator/Chart.yaml index 68402ac9..337ef58c 100644 --- a/charts/pulsar-resources-operator/Chart.yaml +++ b/charts/pulsar-resources-operator/Chart.yaml @@ -30,13 +30,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.14.0-rc.2 +version: v0.14.0-rc.3 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.14.0-rc.2" +appVersion: "v0.14.0-rc.3" # This is a semver range of compatible Kubernetes versions. Helm will validate the version # constraints when installing the chart and fail if the cluster runs an unsupported Kubernetes version From 4cb07f64df5b058439f44b25d5921e7f1281f05c Mon Sep 17 00:00:00 2001 From: Rui Fu Date: Wed, 10 Sep 2025 14:58:49 +0800 Subject: [PATCH 7/7] release v0.14.0 --- charts/pulsar-resources-operator/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/pulsar-resources-operator/Chart.yaml b/charts/pulsar-resources-operator/Chart.yaml index 337ef58c..41f06a61 100644 --- a/charts/pulsar-resources-operator/Chart.yaml +++ b/charts/pulsar-resources-operator/Chart.yaml @@ -30,13 +30,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: v0.14.0-rc.3 +version: v0.14.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "v0.14.0-rc.3" +appVersion: "v0.14.0" # This is a semver range of compatible Kubernetes versions. Helm will validate the version # constraints when installing the chart and fail if the cluster runs an unsupported Kubernetes version