diff --git a/api/v1/infinispan_types.go b/api/v1/infinispan_types.go index e35fddf89..6cb5a3bfa 100644 --- a/api/v1/infinispan_types.go +++ b/api/v1/infinispan_types.go @@ -401,6 +401,13 @@ type ConfigListenerLoggingSpec struct { Level ConfigListenerLogLevel `json:"level"` } +type CryostatSpec struct { + // If true, a JMX endpoint is exposed on the admin service and a Cryostat CR is created to allow JFR recordings to be created via the UI + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Toggle Cryostat",xDescriptors="urn:alm:descriptor:com.tectonic.ui:booleanSwitch" + Enabled bool `json:"enabled,omitempty"` +} + // InfinispanSpec defines the desired state of Infinispan type InfinispanSpec struct { // The number of nodes in the Infinispan cluster. @@ -437,6 +444,8 @@ type InfinispanSpec struct { Upgrades *InfinispanUpgradesSpec `json:"upgrades,omitempty"` // +optional ConfigListener *ConfigListenerSpec `json:"configListener,omitempty"` + // +optional + Cryostat *CryostatSpec `json:"cryostat,omitempty"` } // InfinispanUpgradesSpec defines the Infinispan upgrade strategy diff --git a/api/v1/infinispan_webhook.go b/api/v1/infinispan_webhook.go index bdea774bd..62805dcd3 100644 --- a/api/v1/infinispan_webhook.go +++ b/api/v1/infinispan_webhook.go @@ -139,6 +139,10 @@ func (i *Infinispan) Default() { i.Spec.Service.Sites.Local.Discovery.LaunchGossipRouter = pointer.Bool(true) } } + + if i.Spec.Cryostat == nil { + i.Spec.Cryostat = &CryostatSpec{} + } } // +kubebuilder:webhook:path=/validate-infinispan-org-v1-infinispan,mutating=false,failurePolicy=fail,sideEffects=None,groups=infinispan.org,resources=infinispans,verbs=create;update,versions=v1,name=vinfinispan.kb.io,admissionReviewVersions={v1,v1beta1} @@ -184,6 +188,10 @@ func (i *Infinispan) ValidateUpdate(oldRuntimeObj runtime.Object) error { } } } + + if old.Spec.Cryostat != nil && old.Spec.Cryostat.Enabled != i.Spec.Cryostat.Enabled { + allErrs = append(allErrs, field.Forbidden(field.NewPath("spec").Child("cryostat"), "Cryostat configuration is immutable and cannot be updated after initial Infinispan creation")) + } return errorListToError(i, allErrs) } diff --git a/api/v1/infinispan_webhook_test.go b/api/v1/infinispan_webhook_test.go index d476fac5a..3085c0af5 100644 --- a/api/v1/infinispan_webhook_test.go +++ b/api/v1/infinispan_webhook_test.go @@ -78,6 +78,7 @@ var _ = Describe("Infinispan Webhooks", func() { Expect(spec.Upgrades.Type).Should(Equal(UpgradeTypeShutdown)) Expect(spec.ConfigListener.Enabled).Should(BeTrue()) Expect(spec.ConfigListener.Logging.Level).Should(Equal(ConfigListenerLoggingInfo)) + Expect(spec.Cryostat.Enabled).Should(Equal(false)) }) It("Should initiate DataGrid defaults", func() { @@ -109,6 +110,7 @@ var _ = Describe("Infinispan Webhooks", func() { Expect(spec.Upgrades.Type).Should(Equal(UpgradeTypeShutdown)) Expect(spec.ConfigListener.Enabled).Should(BeTrue()) Expect(spec.ConfigListener.Logging.Level).Should(Equal(ConfigListenerLoggingInfo)) + Expect(spec.Cryostat.Enabled).Should(Equal(false)) }) It("Should calculate default Labels", func() { @@ -574,6 +576,24 @@ var _ = Describe("Infinispan Webhooks", func() { metav1.CauseTypeFieldValueInvalid, "spec.version", "should match", }) }) + + It("Should prevent immutable fields being updated", func() { + ispn := &Infinispan{ + ObjectMeta: metav1.ObjectMeta{ + Name: key.Name, + Namespace: key.Namespace, + }, + Spec: InfinispanSpec{ + Replicas: 1, + }, + } + Expect(k8sClient.Create(ctx, ispn)).Should(Succeed()) + Expect(k8sClient.Get(ctx, key, ispn)).Should(Succeed()) + ispn.Spec.Cryostat.Enabled = true + expectInvalidErrStatus(k8sClient.Update(ctx, ispn), + statusDetailCause{"FieldValueForbidden", "spec.cryostat", "Cryostat configuration is immutable and cannot be updated after initial Infinispan creation"}, + ) + }) }) }) diff --git a/api/v1/types_util.go b/api/v1/types_util.go index 5acf5b3ce..8ff0a2ced 100644 --- a/api/v1/types_util.go +++ b/api/v1/types_util.go @@ -941,3 +941,11 @@ func (ispn *Infinispan) LaunchGossipRouterEnabled() bool { func (ispn *Infinispan) IsGossipRouterEnabled() bool { return ispn.CrossSiteDiscoveryType() == GossipRouterType && ispn.LaunchGossipRouterEnabled() } + +func (ispn *Infinispan) IsCryostatEnabled() bool { + return ispn.Spec.Cryostat != nil && ispn.Spec.Cryostat.Enabled +} + +func (ispn *Infinispan) GetCryostatName() string { + return fmt.Sprintf("%s-cs", ispn.Name) +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 1831b13b2..f4e88d219 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -154,6 +154,21 @@ func (in *CrossSiteTrustStore) DeepCopy() *CrossSiteTrustStore { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CryostatSpec) DeepCopyInto(out *CryostatSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CryostatSpec. +func (in *CryostatSpec) DeepCopy() *CryostatSpec { + if in == nil { + return nil + } + out := new(CryostatSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) { *out = *in @@ -639,6 +654,11 @@ func (in *InfinispanSpec) DeepCopyInto(out *InfinispanSpec) { *out = new(ConfigListenerSpec) (*in).DeepCopyInto(*out) } + if in.Cryostat != nil { + in, out := &in.Cryostat, &out.Cryostat + *out = new(CryostatSpec) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InfinispanSpec. diff --git a/config/crd/bases/infinispan.org_infinispans.yaml b/config/crd/bases/infinispan.org_infinispans.yaml index 9154e958c..77c9851ea 100644 --- a/config/crd/bases/infinispan.org_infinispans.yaml +++ b/config/crd/bases/infinispan.org_infinispans.yaml @@ -708,6 +708,14 @@ spec: routerExtraJvmOpts: type: string type: object + cryostat: + properties: + enabled: + description: If true, a JMX endpoint is exposed on the admin service + and a Cryostat CR is created to allow JFR recordings to be created + via the UI + type: boolean + type: object dependencies: description: External dependencies needed by the Infinispan cluster properties: diff --git a/config/crd/bases/operator.cryostat.io_cryostats.yaml b/config/crd/bases/operator.cryostat.io_cryostats.yaml new file mode 100644 index 000000000..f53975286 --- /dev/null +++ b/config/crd/bases/operator.cryostat.io_cryostats.yaml @@ -0,0 +1,3843 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + name: cryostats.operator.cryostat.io +spec: + group: operator.cryostat.io + names: + kind: Cryostat + listKind: CryostatList + plural: cryostats + singular: cryostat + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.applicationUrl + name: Application URL + type: string + - jsonPath: .status.grafanaSecret + name: Grafana Secret + type: string + name: v1beta1 + schema: + openAPIV3Schema: + description: Cryostat allows you to install Cryostat for a single namespace. + It contains configuration options for controlling the Deployment of the + Cryostat application and its related components. A ClusterCryostat or Cryostat + instance must be created to instruct the operator to deploy the Cryostat + application. + 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: CryostatSpec defines the desired state of Cryostat. + properties: + authProperties: + description: Override default authorization properties for Cryostat + on OpenShift. + properties: + clusterRoleName: + description: 'Name of the ClusterRole to use when Cryostat requests + a role-scoped OAuth token. This ClusterRole should contain permissions + for all Kubernetes objects listed in custom permission mapping. + More details: https://docs.openshift.com/container-platform/4.11/authentication/tokens-scoping.html#scoping-tokens-role-scope_configuring-internal-oauth' + type: string + configMapName: + description: Name of config map in the local namespace. + type: string + filename: + description: Filename within config map containing the resource + mapping. + type: string + required: + - clusterRoleName + - configMapName + - filename + type: object + enableCertManager: + description: Use cert-manager to secure in-cluster communication between + Cryostat components. Requires cert-manager to be installed. + type: boolean + eventTemplates: + description: List of Flight Recorder Event Templates to preconfigure + in Cryostat. + items: + description: A ConfigMap containing a .jfc template file. + properties: + configMapName: + description: Name of config map in the local namespace. + type: string + filename: + description: Filename within config map containing the template + file. + type: string + required: + - configMapName + - filename + type: object + type: array + jmxCacheOptions: + description: Options to customize the JMX target connections cache + for the Cryostat application. + properties: + targetCacheSize: + description: The maximum number of JMX connections to cache. Use + `-1` for an unlimited cache size (TTL expiration only). Defaults + to `-1`. + format: int32 + minimum: -1 + type: integer + targetCacheTTL: + description: The time to live (in seconds) for cached JMX connections. + Defaults to `10`. + format: int32 + minimum: 1 + type: integer + type: object + jmxCredentialsDatabaseOptions: + description: Options to configure the Cryostat application's credentials + database. + properties: + databaseSecretName: + description: Name of the secret containing the password to encrypt + credentials database. + type: string + type: object + maxWsConnections: + description: The maximum number of WebSocket client connections allowed + (minimum 1, default unlimited). + format: int32 + minimum: 1 + type: integer + minimal: + description: Deploy a pared-down Cryostat instance with no Grafana + Dashboard or JFR Data Source. + type: boolean + networkOptions: + description: Options to control how the operator exposes the application + outside of the cluster, such as using an Ingress or Route. + properties: + commandConfig: + description: "Specifications for how to expose the Cryostat command + service, which serves the WebSocket command channel. \n Deprecated: + CommandConfig is no longer used." + properties: + annotations: + additionalProperties: + type: string + description: Annotations to add to the Ingress or Route during + its creation. + type: object + ingressSpec: + description: Configuration for an Ingress object. Currently + subpaths are not supported, so unique hosts must be specified + (if a single external IP is being used) to differentiate + between ingresses/services. + properties: + defaultBackend: + description: DefaultBackend is the backend that should + handle requests that don't match any rule. If Rules + are not specified, DefaultBackend must be specified. + If DefaultBackend is not set, the handling of requests + that do not match any of the rules will be up to the + Ingress controller. + properties: + resource: + description: Resource is an ObjectRef to another Kubernetes + resource in the namespace of the Ingress object. + If resource is specified, a service.Name and service.Port + must not be specified. This is a mutually exclusive + setting with "Service". + properties: + apiGroup: + description: APIGroup is the group for the resource + being referenced. If APIGroup is not specified, + the specified Kind must be in the core API group. + For any other third-party types, APIGroup is + required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + required: + - kind + - name + type: object + service: + description: Service references a Service as a Backend. + This is a mutually exclusive setting with "Resource". + properties: + name: + description: Name is the referenced service. The + service must exist in the same namespace as + the Ingress object. + type: string + port: + description: Port of the referenced service. A + port name or port number is required for a IngressServiceBackend. + properties: + name: + description: Name is the name of the port + on the Service. This is a mutually exclusive + setting with "Number". + type: string + number: + description: Number is the numerical port + number (e.g. 80) on the Service. This is + a mutually exclusive setting with "Name". + format: int32 + type: integer + type: object + required: + - name + type: object + type: object + ingressClassName: + description: IngressClassName is the name of the IngressClass + cluster resource. The associated IngressClass defines + which controller will implement the resource. This replaces + the deprecated `kubernetes.io/ingress.class` annotation. + For backwards compatibility, when that annotation is + set, it must be given precedence over this field. The + controller may emit a warning if the field and annotation + have different values. Implementations of this API should + ignore Ingresses without a class specified. An IngressClass + resource may be marked as default, which can be used + to set a default value for this field. For more information, + refer to the IngressClass documentation. + type: string + rules: + description: A list of host rules used to configure the + Ingress. If unspecified, or no rule matches, all traffic + is sent to the default backend. + items: + description: IngressRule represents the rules mapping + the paths under a specified host to the related backend + services. Incoming requests are first evaluated for + a host match, then routed to the backend associated + with the matching IngressRuleValue. + properties: + host: + description: "Host is the fully qualified domain + name of a network host, as defined by RFC 3986. + Note the following deviations from the \"host\" + part of the URI as defined in RFC 3986: 1. IPs + are not allowed. Currently an IngressRuleValue + can only apply to the IP in the Spec of the + parent Ingress. 2. The `:` delimiter is not respected + because ports are not allowed. \t Currently the + port of an Ingress is implicitly :80 for http + and \t :443 for https. Both these may change + in the future. Incoming requests are matched against + the host before the IngressRuleValue. If the host + is unspecified, the Ingress routes all traffic + based on the specified IngressRuleValue. \n Host + can be \"precise\" which is a domain name without + the terminating dot of a network host (e.g. \"foo.bar.com\") + or \"wildcard\", which is a domain name prefixed + with a single wildcard label (e.g. \"*.foo.com\"). + The wildcard character '*' must appear by itself + as the first DNS label and matches only a single + label. You cannot have a wildcard label by itself + (e.g. Host == \"*\"). Requests will be matched + against the Host field in the following way: 1. + If Host is precise, the request matches this rule + if the http host header is equal to Host. 2. If + Host is a wildcard, then the request matches this + rule if the http host header is to equal to the + suffix (removing the first label) of the wildcard + rule." + type: string + http: + description: 'HTTPIngressRuleValue is a list of + http selectors pointing to backends. In the example: + http:///? -> backend where + where parts of the url correspond to RFC 3986, + this resource will be used to match against everything + after the last ''/'' and before the first ''?'' + or ''#''.' + properties: + paths: + description: A collection of paths that map + requests to backends. + items: + description: HTTPIngressPath associates a + path with a backend. Incoming urls matching + the path are forwarded to the backend. + properties: + backend: + description: Backend defines the referenced + service endpoint to which the traffic + will be forwarded to. + properties: + resource: + description: Resource is an ObjectRef + to another Kubernetes resource in + the namespace of the Ingress object. + If resource is specified, a service.Name + and service.Port must not be specified. + This is a mutually exclusive setting + with "Service". + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + service: + description: Service references a + Service as a Backend. This is a + mutually exclusive setting with + "Resource". + properties: + name: + description: Name is the referenced + service. The service must exist + in the same namespace as the + Ingress object. + type: string + port: + description: Port of the referenced + service. A port name or port + number is required for a IngressServiceBackend. + properties: + name: + description: Name is the name + of the port on the Service. + This is a mutually exclusive + setting with "Number". + type: string + number: + description: Number is the + numerical port number (e.g. + 80) on the Service. This + is a mutually exclusive + setting with "Name". + format: int32 + type: integer + type: object + required: + - name + type: object + type: object + path: + description: Path is matched against the + path of an incoming request. Currently + it can contain characters disallowed + from the conventional "path" part of + a URL as defined by RFC 3986. Paths + must begin with a '/'. When unspecified, + all paths from incoming requests are + matched. + type: string + pathType: + description: 'PathType determines the + interpretation of the Path matching. + PathType can be one of the following + values: * Exact: Matches the URL path + exactly. * Prefix: Matches based on + a URL path prefix split by ''/''. Matching + is done on a path element by element + basis. A path element refers is the list + of labels in the path split by the ''/'' + separator. A request is a match for + path p if every p is an element-wise + prefix of p of the request path. Note + that if the last element of the path + is a substring of the last element + in request path, it is not a match (e.g. + /foo/bar matches /foo/bar/baz, but + does not match /foo/barbaz). * ImplementationSpecific: + Interpretation of the Path matching + is up to the IngressClass. Implementations + can treat this as a separate PathType or + treat it identically to Prefix or Exact + path types. Implementations are required + to support all path types.' + type: string + required: + - backend + type: object + type: array + x-kubernetes-list-type: atomic + required: + - paths + type: object + type: object + type: array + x-kubernetes-list-type: atomic + tls: + description: TLS configuration. Currently the Ingress + only supports a single TLS port, 443. If multiple members + of this list specify different hosts, they will be multiplexed + on the same port according to the hostname specified + through the SNI TLS extension, if the ingress controller + fulfilling the ingress supports SNI. + items: + description: IngressTLS describes the transport layer + security associated with an Ingress. + properties: + hosts: + description: Hosts are a list of hosts included + in the TLS certificate. The values in this list + must match the name/s used in the tlsSecret. Defaults + to the wildcard host setting for the loadbalancer + controller fulfilling this Ingress, if left unspecified. + items: + type: string + type: array + x-kubernetes-list-type: atomic + secretName: + description: SecretName is the name of the secret + used to terminate TLS traffic on port 443. Field + is left optional to allow TLS routing based on + SNI hostname alone. If the SNI host in a listener + conflicts with the "Host" header field used by + an IngressRule, the SNI host is used for termination + and value of the Host header is used for routing. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + labels: + additionalProperties: + type: string + description: Labels to add to the Ingress or Route during + its creation. The label with key "app" is reserved for use + by the operator. + type: object + type: object + coreConfig: + description: Specifications for how to expose the Cryostat service, + which serves the Cryostat application. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to add to the Ingress or Route during + its creation. + type: object + ingressSpec: + description: Configuration for an Ingress object. Currently + subpaths are not supported, so unique hosts must be specified + (if a single external IP is being used) to differentiate + between ingresses/services. + properties: + defaultBackend: + description: DefaultBackend is the backend that should + handle requests that don't match any rule. If Rules + are not specified, DefaultBackend must be specified. + If DefaultBackend is not set, the handling of requests + that do not match any of the rules will be up to the + Ingress controller. + properties: + resource: + description: Resource is an ObjectRef to another Kubernetes + resource in the namespace of the Ingress object. + If resource is specified, a service.Name and service.Port + must not be specified. This is a mutually exclusive + setting with "Service". + properties: + apiGroup: + description: APIGroup is the group for the resource + being referenced. If APIGroup is not specified, + the specified Kind must be in the core API group. + For any other third-party types, APIGroup is + required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + required: + - kind + - name + type: object + service: + description: Service references a Service as a Backend. + This is a mutually exclusive setting with "Resource". + properties: + name: + description: Name is the referenced service. The + service must exist in the same namespace as + the Ingress object. + type: string + port: + description: Port of the referenced service. A + port name or port number is required for a IngressServiceBackend. + properties: + name: + description: Name is the name of the port + on the Service. This is a mutually exclusive + setting with "Number". + type: string + number: + description: Number is the numerical port + number (e.g. 80) on the Service. This is + a mutually exclusive setting with "Name". + format: int32 + type: integer + type: object + required: + - name + type: object + type: object + ingressClassName: + description: IngressClassName is the name of the IngressClass + cluster resource. The associated IngressClass defines + which controller will implement the resource. This replaces + the deprecated `kubernetes.io/ingress.class` annotation. + For backwards compatibility, when that annotation is + set, it must be given precedence over this field. The + controller may emit a warning if the field and annotation + have different values. Implementations of this API should + ignore Ingresses without a class specified. An IngressClass + resource may be marked as default, which can be used + to set a default value for this field. For more information, + refer to the IngressClass documentation. + type: string + rules: + description: A list of host rules used to configure the + Ingress. If unspecified, or no rule matches, all traffic + is sent to the default backend. + items: + description: IngressRule represents the rules mapping + the paths under a specified host to the related backend + services. Incoming requests are first evaluated for + a host match, then routed to the backend associated + with the matching IngressRuleValue. + properties: + host: + description: "Host is the fully qualified domain + name of a network host, as defined by RFC 3986. + Note the following deviations from the \"host\" + part of the URI as defined in RFC 3986: 1. IPs + are not allowed. Currently an IngressRuleValue + can only apply to the IP in the Spec of the + parent Ingress. 2. The `:` delimiter is not respected + because ports are not allowed. \t Currently the + port of an Ingress is implicitly :80 for http + and \t :443 for https. Both these may change + in the future. Incoming requests are matched against + the host before the IngressRuleValue. If the host + is unspecified, the Ingress routes all traffic + based on the specified IngressRuleValue. \n Host + can be \"precise\" which is a domain name without + the terminating dot of a network host (e.g. \"foo.bar.com\") + or \"wildcard\", which is a domain name prefixed + with a single wildcard label (e.g. \"*.foo.com\"). + The wildcard character '*' must appear by itself + as the first DNS label and matches only a single + label. You cannot have a wildcard label by itself + (e.g. Host == \"*\"). Requests will be matched + against the Host field in the following way: 1. + If Host is precise, the request matches this rule + if the http host header is equal to Host. 2. If + Host is a wildcard, then the request matches this + rule if the http host header is to equal to the + suffix (removing the first label) of the wildcard + rule." + type: string + http: + description: 'HTTPIngressRuleValue is a list of + http selectors pointing to backends. In the example: + http:///? -> backend where + where parts of the url correspond to RFC 3986, + this resource will be used to match against everything + after the last ''/'' and before the first ''?'' + or ''#''.' + properties: + paths: + description: A collection of paths that map + requests to backends. + items: + description: HTTPIngressPath associates a + path with a backend. Incoming urls matching + the path are forwarded to the backend. + properties: + backend: + description: Backend defines the referenced + service endpoint to which the traffic + will be forwarded to. + properties: + resource: + description: Resource is an ObjectRef + to another Kubernetes resource in + the namespace of the Ingress object. + If resource is specified, a service.Name + and service.Port must not be specified. + This is a mutually exclusive setting + with "Service". + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + service: + description: Service references a + Service as a Backend. This is a + mutually exclusive setting with + "Resource". + properties: + name: + description: Name is the referenced + service. The service must exist + in the same namespace as the + Ingress object. + type: string + port: + description: Port of the referenced + service. A port name or port + number is required for a IngressServiceBackend. + properties: + name: + description: Name is the name + of the port on the Service. + This is a mutually exclusive + setting with "Number". + type: string + number: + description: Number is the + numerical port number (e.g. + 80) on the Service. This + is a mutually exclusive + setting with "Name". + format: int32 + type: integer + type: object + required: + - name + type: object + type: object + path: + description: Path is matched against the + path of an incoming request. Currently + it can contain characters disallowed + from the conventional "path" part of + a URL as defined by RFC 3986. Paths + must begin with a '/'. When unspecified, + all paths from incoming requests are + matched. + type: string + pathType: + description: 'PathType determines the + interpretation of the Path matching. + PathType can be one of the following + values: * Exact: Matches the URL path + exactly. * Prefix: Matches based on + a URL path prefix split by ''/''. Matching + is done on a path element by element + basis. A path element refers is the list + of labels in the path split by the ''/'' + separator. A request is a match for + path p if every p is an element-wise + prefix of p of the request path. Note + that if the last element of the path + is a substring of the last element + in request path, it is not a match (e.g. + /foo/bar matches /foo/bar/baz, but + does not match /foo/barbaz). * ImplementationSpecific: + Interpretation of the Path matching + is up to the IngressClass. Implementations + can treat this as a separate PathType or + treat it identically to Prefix or Exact + path types. Implementations are required + to support all path types.' + type: string + required: + - backend + type: object + type: array + x-kubernetes-list-type: atomic + required: + - paths + type: object + type: object + type: array + x-kubernetes-list-type: atomic + tls: + description: TLS configuration. Currently the Ingress + only supports a single TLS port, 443. If multiple members + of this list specify different hosts, they will be multiplexed + on the same port according to the hostname specified + through the SNI TLS extension, if the ingress controller + fulfilling the ingress supports SNI. + items: + description: IngressTLS describes the transport layer + security associated with an Ingress. + properties: + hosts: + description: Hosts are a list of hosts included + in the TLS certificate. The values in this list + must match the name/s used in the tlsSecret. Defaults + to the wildcard host setting for the loadbalancer + controller fulfilling this Ingress, if left unspecified. + items: + type: string + type: array + x-kubernetes-list-type: atomic + secretName: + description: SecretName is the name of the secret + used to terminate TLS traffic on port 443. Field + is left optional to allow TLS routing based on + SNI hostname alone. If the SNI host in a listener + conflicts with the "Host" header field used by + an IngressRule, the SNI host is used for termination + and value of the Host header is used for routing. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + labels: + additionalProperties: + type: string + description: Labels to add to the Ingress or Route during + its creation. The label with key "app" is reserved for use + by the operator. + type: object + type: object + grafanaConfig: + description: Specifications for how to expose Cryostat's Grafana + service, which serves the Grafana dashboard. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to add to the Ingress or Route during + its creation. + type: object + ingressSpec: + description: Configuration for an Ingress object. Currently + subpaths are not supported, so unique hosts must be specified + (if a single external IP is being used) to differentiate + between ingresses/services. + properties: + defaultBackend: + description: DefaultBackend is the backend that should + handle requests that don't match any rule. If Rules + are not specified, DefaultBackend must be specified. + If DefaultBackend is not set, the handling of requests + that do not match any of the rules will be up to the + Ingress controller. + properties: + resource: + description: Resource is an ObjectRef to another Kubernetes + resource in the namespace of the Ingress object. + If resource is specified, a service.Name and service.Port + must not be specified. This is a mutually exclusive + setting with "Service". + properties: + apiGroup: + description: APIGroup is the group for the resource + being referenced. If APIGroup is not specified, + the specified Kind must be in the core API group. + For any other third-party types, APIGroup is + required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + required: + - kind + - name + type: object + service: + description: Service references a Service as a Backend. + This is a mutually exclusive setting with "Resource". + properties: + name: + description: Name is the referenced service. The + service must exist in the same namespace as + the Ingress object. + type: string + port: + description: Port of the referenced service. A + port name or port number is required for a IngressServiceBackend. + properties: + name: + description: Name is the name of the port + on the Service. This is a mutually exclusive + setting with "Number". + type: string + number: + description: Number is the numerical port + number (e.g. 80) on the Service. This is + a mutually exclusive setting with "Name". + format: int32 + type: integer + type: object + required: + - name + type: object + type: object + ingressClassName: + description: IngressClassName is the name of the IngressClass + cluster resource. The associated IngressClass defines + which controller will implement the resource. This replaces + the deprecated `kubernetes.io/ingress.class` annotation. + For backwards compatibility, when that annotation is + set, it must be given precedence over this field. The + controller may emit a warning if the field and annotation + have different values. Implementations of this API should + ignore Ingresses without a class specified. An IngressClass + resource may be marked as default, which can be used + to set a default value for this field. For more information, + refer to the IngressClass documentation. + type: string + rules: + description: A list of host rules used to configure the + Ingress. If unspecified, or no rule matches, all traffic + is sent to the default backend. + items: + description: IngressRule represents the rules mapping + the paths under a specified host to the related backend + services. Incoming requests are first evaluated for + a host match, then routed to the backend associated + with the matching IngressRuleValue. + properties: + host: + description: "Host is the fully qualified domain + name of a network host, as defined by RFC 3986. + Note the following deviations from the \"host\" + part of the URI as defined in RFC 3986: 1. IPs + are not allowed. Currently an IngressRuleValue + can only apply to the IP in the Spec of the + parent Ingress. 2. The `:` delimiter is not respected + because ports are not allowed. \t Currently the + port of an Ingress is implicitly :80 for http + and \t :443 for https. Both these may change + in the future. Incoming requests are matched against + the host before the IngressRuleValue. If the host + is unspecified, the Ingress routes all traffic + based on the specified IngressRuleValue. \n Host + can be \"precise\" which is a domain name without + the terminating dot of a network host (e.g. \"foo.bar.com\") + or \"wildcard\", which is a domain name prefixed + with a single wildcard label (e.g. \"*.foo.com\"). + The wildcard character '*' must appear by itself + as the first DNS label and matches only a single + label. You cannot have a wildcard label by itself + (e.g. Host == \"*\"). Requests will be matched + against the Host field in the following way: 1. + If Host is precise, the request matches this rule + if the http host header is equal to Host. 2. If + Host is a wildcard, then the request matches this + rule if the http host header is to equal to the + suffix (removing the first label) of the wildcard + rule." + type: string + http: + description: 'HTTPIngressRuleValue is a list of + http selectors pointing to backends. In the example: + http:///? -> backend where + where parts of the url correspond to RFC 3986, + this resource will be used to match against everything + after the last ''/'' and before the first ''?'' + or ''#''.' + properties: + paths: + description: A collection of paths that map + requests to backends. + items: + description: HTTPIngressPath associates a + path with a backend. Incoming urls matching + the path are forwarded to the backend. + properties: + backend: + description: Backend defines the referenced + service endpoint to which the traffic + will be forwarded to. + properties: + resource: + description: Resource is an ObjectRef + to another Kubernetes resource in + the namespace of the Ingress object. + If resource is specified, a service.Name + and service.Port must not be specified. + This is a mutually exclusive setting + with "Service". + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + service: + description: Service references a + Service as a Backend. This is a + mutually exclusive setting with + "Resource". + properties: + name: + description: Name is the referenced + service. The service must exist + in the same namespace as the + Ingress object. + type: string + port: + description: Port of the referenced + service. A port name or port + number is required for a IngressServiceBackend. + properties: + name: + description: Name is the name + of the port on the Service. + This is a mutually exclusive + setting with "Number". + type: string + number: + description: Number is the + numerical port number (e.g. + 80) on the Service. This + is a mutually exclusive + setting with "Name". + format: int32 + type: integer + type: object + required: + - name + type: object + type: object + path: + description: Path is matched against the + path of an incoming request. Currently + it can contain characters disallowed + from the conventional "path" part of + a URL as defined by RFC 3986. Paths + must begin with a '/'. When unspecified, + all paths from incoming requests are + matched. + type: string + pathType: + description: 'PathType determines the + interpretation of the Path matching. + PathType can be one of the following + values: * Exact: Matches the URL path + exactly. * Prefix: Matches based on + a URL path prefix split by ''/''. Matching + is done on a path element by element + basis. A path element refers is the list + of labels in the path split by the ''/'' + separator. A request is a match for + path p if every p is an element-wise + prefix of p of the request path. Note + that if the last element of the path + is a substring of the last element + in request path, it is not a match (e.g. + /foo/bar matches /foo/bar/baz, but + does not match /foo/barbaz). * ImplementationSpecific: + Interpretation of the Path matching + is up to the IngressClass. Implementations + can treat this as a separate PathType or + treat it identically to Prefix or Exact + path types. Implementations are required + to support all path types.' + type: string + required: + - backend + type: object + type: array + x-kubernetes-list-type: atomic + required: + - paths + type: object + type: object + type: array + x-kubernetes-list-type: atomic + tls: + description: TLS configuration. Currently the Ingress + only supports a single TLS port, 443. If multiple members + of this list specify different hosts, they will be multiplexed + on the same port according to the hostname specified + through the SNI TLS extension, if the ingress controller + fulfilling the ingress supports SNI. + items: + description: IngressTLS describes the transport layer + security associated with an Ingress. + properties: + hosts: + description: Hosts are a list of hosts included + in the TLS certificate. The values in this list + must match the name/s used in the tlsSecret. Defaults + to the wildcard host setting for the loadbalancer + controller fulfilling this Ingress, if left unspecified. + items: + type: string + type: array + x-kubernetes-list-type: atomic + secretName: + description: SecretName is the name of the secret + used to terminate TLS traffic on port 443. Field + is left optional to allow TLS routing based on + SNI hostname alone. If the SNI host in a listener + conflicts with the "Host" header field used by + an IngressRule, the SNI host is used for termination + and value of the Host header is used for routing. + type: string + type: object + type: array + x-kubernetes-list-type: atomic + type: object + labels: + additionalProperties: + type: string + description: Labels to add to the Ingress or Route during + its creation. The label with key "app" is reserved for use + by the operator. + type: object + type: object + type: object + reportOptions: + description: Options to configure Cryostat Automated Report Analysis. + properties: + replicas: + description: The number of report sidecar replica containers to + deploy. Each replica can service one report generation request + at a time. + format: int32 + type: integer + resources: + description: The resources allocated to each sidecar replica. + A replica with more resources can handle larger input recordings + and will process them faster. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + type: object + schedulingOptions: + description: Options to configure scheduling for the reports deployment + properties: + affinity: + description: Affinity rules for scheduling Cryostat pods. + properties: + nodeAffinity: + description: 'Node affinity scheduling rules for a Cryostat + pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#NodeAffinity' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the + greatest sum of weights, i.e. for each node that + meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, + etc.), compute a sum by iterating through the elements + of this field and adding "weight" to the sum if + the node matches the corresponding matchExpressions; + the node(s) with the highest sum are the most preferred. + items: + description: An empty preferred scheduling term + matches all objects with implicit weight 0 (i.e. + it's a no-op). A null preferred scheduling term + matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, in the + range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the + affinity requirements specified by this field cease + to be met at some point during pod execution (e.g. + due to an update), the system may or may not try + to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: A null or empty node selector term + matches no objects. The requirements of them + are ANDed. The TopologySelectorTerm type implements + a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the + selector applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, the + values array must have a single + element, which will be interpreted + as an integer. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms + type: object + type: object + podAffinity: + description: 'Pod affinity scheduling rules for a Cryostat + pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodAffinity' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the + greatest sum of weights, i.e. for each node that + meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, + etc.), compute a sum by iterating through the elements + of this field and adding "weight" to the sum if + the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest sum + are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of + resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which + namespaces the labelSelector applies to + (matches against); null or empty list + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in the + range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the + affinity requirements specified by this field cease + to be met at some point during pod execution (e.g. + due to a pod label update), the system may or may + not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes + corresponding to each podAffinityTerm are intersected, + i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those + matching the labelSelector relative to the given + namespace(s)) that this pod should be co-located + (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node + whose value of the label with key + matches that of any node on which a pod of the + set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which namespaces + the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the + pods matching the labelSelector in the specified + namespaces, where co-located is defined as + running on a node whose value of the label + with key topologyKey matches that of any node + on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: 'Pod anti-affinity scheduling rules for a + Cryostat pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodAntiAffinity' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the anti-affinity expressions + specified by this field, but it may choose a node + that violates one or more of the expressions. The + node that is most preferred is the one with the + greatest sum of weights, i.e. for each node that + meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity + expressions, etc.), compute a sum by iterating through + the elements of this field and adding "weight" to + the sum if the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest sum + are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, + associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of + resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The + requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a set + of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values array + must be non-empty. If the operator + is Exists or DoesNotExist, the + values array must be empty. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of + {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which + namespaces the labelSelector applies to + (matches against); null or empty list + means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in the + range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified + by this field are not met at scheduling time, the + pod will not be scheduled onto the node. If the + anti-affinity requirements specified by this field + cease to be met at some point during pod execution + (e.g. due to a pod label update), the system may + or may not try to eventually evict the pod from + its node. When there are multiple elements, the + lists of nodes corresponding to each podAffinityTerm + are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those + matching the labelSelector relative to the given + namespace(s)) that this pod should be co-located + (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node + whose value of the label with key + matches that of any node on which a pod of the + set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which namespaces + the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the + pods matching the labelSelector in the specified + namespaces, where co-located is defined as + running on a node whose value of the label + with key topologyKey matches that of any node + on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: 'Label selector used to schedule a Cryostat pod + to a node. See: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + tolerations: + description: 'Tolerations to allow scheduling of Cryostat + pods to tainted nodes. See: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/' + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period + of time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration + matches to. If the operator is Exists, the value should + be empty, otherwise just a regular string. + type: string + type: object + type: array + type: object + securityOptions: + description: Options to configure the Security Contexts for the + Cryostat report generator. + properties: + podSecurityContext: + description: Security Context to apply to the Cryostat report + generator pod. + properties: + fsGroup: + description: "A special supplemental group that applies + to all containers in a pod. Some volume types allow + the Kubelet to change the ownership of that volume to + be owned by the pod: \n 1. The owning GID will be the + FSGroup 2. The setgid bit is set (new files created + in the volume will be owned by FSGroup) 3. The permission + bits are OR'd with rw-rw---- \n If unset, the Kubelet + will not modify the ownership and permissions of any + volume." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of + changing ownership and permission of the volume before + being exposed inside Pod. This field will only apply + to volume types which support fsGroup based ownership(and + permissions). It will have no effect on ephemeral volume + types such as: secret, configmaps and emptydir. Valid + values are "OnRootMismatch" and "Always". If not specified + defaults to "Always".' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in SecurityContext. If set + in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to all + containers. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first process + run in each container, in addition to the container's + primary GID. If unspecified, no groups will be added + to any container. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls (by + the container runtime) might fail to launch. + items: + description: Sysctl defines a kernel parameter to be + set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options within a + container's SecurityContext will be used. If set in + both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + reportsSecurityContext: + description: Security Context to apply to the Cryostat report + generator container. + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether + a process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag + will be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN' + type: boolean + capabilities: + description: The capabilities to add/drop when running + containers. Defaults to the default set of capabilities + granted by the container runtime. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent + to root on the host. Defaults to false. + type: boolean + procMount: + description: procMount denotes the type of proc mount + to use for the containers. The default is DefaultProcMount + which uses the container runtime defaults for readonly + paths and masked paths. This requires the ProcMountType + feature flag to be enabled. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root + filesystem. Default is false. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as + a non-root user. If true, the Kubelet will validate + the image at runtime to ensure that it does not run + as UID 0 (root) and fail to start the container if it + does. If unset or false, no such validation will be + performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata + if unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the + container. If unspecified, the container runtime will + allocate a random SELinux context for each container. May + also be set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. The + profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's + configured seccomp profile location. Must only be + set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: \n Localhost + - a profile defined in a file on the node should + be used. RuntimeDefault - the container runtime + default profile should be used. Unconfined - no + profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to + all containers. If unspecified, the options from the + PodSecurityContext will be used. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA + admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec + named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of + the GMSA credential spec to use. + type: string + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + type: object + subProcessMaxHeapSize: + description: When zero report sidecar replicas are requested, + SubProcessMaxHeapSize configures the maximum heap size of the + basic subprocess report generator in MiB. The default heap size + is `200` (MiB). + format: int32 + type: integer + type: object + resources: + description: Resource requirements for the Cryostat deployment. + properties: + coreResources: + description: Resource requirements for the Cryostat application. + If specifying a memory limit, at least 768MiB is recommended. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + type: object + dataSourceResources: + description: Resource requirements for the JFR Data Source container. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + type: object + grafanaResources: + description: Resource requirements for the Grafana container. + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + type: object + type: object + schedulingOptions: + description: Options to configure scheduling for the Cryostat deployment + properties: + affinity: + description: Affinity rules for scheduling Cryostat pods. + properties: + nodeAffinity: + description: 'Node affinity scheduling rules for a Cryostat + pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#NodeAffinity' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the affinity expressions specified + by this field, but it may choose a node that violates + one or more of the expressions. The node that is most + preferred is the one with the greatest sum of weights, + i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" + to the sum if the node matches the corresponding matchExpressions; + the node(s) with the highest sum are the most preferred. + items: + description: An empty preferred scheduling term matches + all objects with implicit weight 0 (i.e. it's a no-op). + A null preferred scheduling term matches no objects + (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with + the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement is + a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. If the + operator is Gt or Lt, the values array + must have a single element, which will + be interpreted as an integer. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement is + a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. If the + operator is Gt or Lt, the values array + must have a single element, which will + be interpreted as an integer. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + weight: + description: Weight associated with matching the + corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by + this field are not met at scheduling time, the pod will + not be scheduled onto the node. If the affinity requirements + specified by this field cease to be met at some point + during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from + its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: A null or empty node selector term + matches no objects. The requirements of them are + ANDed. The TopologySelectorTerm type implements + a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: A node selector requirement is + a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. If the + operator is Gt or Lt, the values array + must have a single element, which will + be interpreted as an integer. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: A node selector requirement is + a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: Represents a key's relationship + to a set of values. Valid operators + are In, NotIn, Exists, DoesNotExist. + Gt, and Lt. + type: string + values: + description: An array of string values. + If the operator is In or NotIn, the + values array must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. If the + operator is Gt or Lt, the values array + must have a single element, which will + be interpreted as an integer. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms + type: object + type: object + podAffinity: + description: 'Pod affinity scheduling rules for a Cryostat + pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodAffinity' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the affinity expressions specified + by this field, but it may choose a node that violates + one or more of the expressions. The node that is most + preferred is the one with the greatest sum of weights, + i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" + to the sum if the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest sum are + the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which namespaces + the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the + pods matching the labelSelector in the specified + namespaces, where co-located is defined as + running on a node whose value of the label + with key topologyKey matches that of any node + on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the + corresponding podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by + this field are not met at scheduling time, the pod will + not be scheduled onto the node. If the affinity requirements + specified by this field cease to be met at some point + during pod execution (e.g. due to a pod label update), + the system may or may not try to eventually evict the + pod from its node. When there are multiple elements, + the lists of nodes corresponding to each podAffinityTerm + are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or not + co-located (anti-affinity) with, where co-located + is defined as running on a node whose value of the + label with key matches that of any node + on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which namespaces + the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified namespaces, + where co-located is defined as running on a node + whose value of the label with key topologyKey + matches that of any node on which any of the selected + pods is running. Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: 'Pod anti-affinity scheduling rules for a Cryostat + pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodAntiAffinity' + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods + to nodes that satisfy the anti-affinity expressions + specified by this field, but it may choose a node that + violates one or more of the expressions. The node that + is most preferred is the one with the greatest sum of + weights, i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + anti-affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" + to the sum if the node has pods which matches the corresponding + podAffinityTerm; the node(s) with the highest sum are + the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred + node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list + of label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key + that the selector applies to. + type: string + operator: + description: operator represents a + key's relationship to a set of values. + Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of + string values. If the operator is + In or NotIn, the values array must + be non-empty. If the operator is + Exists or DoesNotExist, the values + array must be empty. This array + is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which namespaces + the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the + pods matching the labelSelector in the specified + namespaces, where co-located is defined as + running on a node whose value of the label + with key topologyKey matches that of any node + on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the + corresponding podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified + by this field are not met at scheduling time, the pod + will not be scheduled onto the node. If the anti-affinity + requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod + label update), the system may or may not try to eventually + evict the pod from its node. When there are multiple + elements, the lists of nodes corresponding to each podAffinityTerm + are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those matching + the labelSelector relative to the given namespace(s)) + that this pod should be co-located (affinity) or not + co-located (anti-affinity) with, where co-located + is defined as running on a node whose value of the + label with key matches that of any node + on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: A label selector requirement + is a selector that contains values, a key, + and an operator that relates the key and + values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only "value". + The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies which namespaces + the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods + matching the labelSelector in the specified namespaces, + where co-located is defined as running on a node + whose value of the label with key topologyKey + matches that of any node on which any of the selected + pods is running. Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + nodeSelector: + additionalProperties: + type: string + description: 'Label selector used to schedule a Cryostat pod to + a node. See: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + tolerations: + description: 'Tolerations to allow scheduling of Cryostat pods + to tainted nodes. See: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/' + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, allowed + values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies + to. Empty means match all taint keys. If the key is empty, + operator must be Exists; this combination means to match + all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to + the value. Valid operators are Exists and Equal. Defaults + to Equal. Exists is equivalent to wildcard for value, + so that a pod can tolerate all taints of a particular + category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the taint + forever (do not evict). Zero and negative values will + be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + type: object + securityOptions: + description: Options to configure the Security Contexts for the Cryostat + application. + properties: + coreSecurityContext: + description: Security Context to apply to the Cryostat application + container. + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a + process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the + container runtime. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes in + privileged containers are essentially equivalent to root + on the host. Defaults to false. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use + for the containers. The default is DefaultProcMount which + uses the container runtime defaults for readonly paths and + masked paths. This requires the ProcMountType feature flag + to be enabled. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. + Default is false. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be set + in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail + to start the container if it does. If unset or false, no + such validation will be performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata if + unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in + PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must + be preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a + profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile + should be used. Unconfined - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to all + containers. If unspecified, the options from the PodSecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named + by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in + PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + dataSourceSecurityContext: + description: Security Context to apply to the JFR Data Source + container. + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a + process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the + container runtime. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes in + privileged containers are essentially equivalent to root + on the host. Defaults to false. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use + for the containers. The default is DefaultProcMount which + uses the container runtime defaults for readonly paths and + masked paths. This requires the ProcMountType feature flag + to be enabled. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. + Default is false. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be set + in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail + to start the container if it does. If unset or false, no + such validation will be performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata if + unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in + PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must + be preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a + profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile + should be used. Unconfined - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to all + containers. If unspecified, the options from the PodSecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named + by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in + PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + grafanaSecurityContext: + description: Security Context to apply to the Grafana container. + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a + process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the + container runtime. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes in + privileged containers are essentially equivalent to root + on the host. Defaults to false. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use + for the containers. The default is DefaultProcMount which + uses the container runtime defaults for readonly paths and + masked paths. This requires the ProcMountType feature flag + to be enabled. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. + Default is false. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be set + in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail + to start the container if it does. If unset or false, no + such validation will be performed. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata if + unspecified. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in + PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must + be preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a + profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile + should be used. Unconfined - no profile should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings applied to all + containers. If unspecified, the options from the PodSecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named + by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in + PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + podSecurityContext: + description: Security Context to apply to the Cryostat pod. + properties: + fsGroup: + description: "A special supplemental group that applies to + all containers in a pod. Some volume types allow the Kubelet + to change the ownership of that volume to be owned by the + pod: \n 1. The owning GID will be the FSGroup 2. The setgid + bit is set (new files created in the volume will be owned + by FSGroup) 3. The permission bits are OR'd with rw-rw---- + \n If unset, the Kubelet will not modify the ownership and + permissions of any volume." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of changing + ownership and permission of the volume before being exposed + inside Pod. This field will only apply to volume types which + support fsGroup based ownership(and permissions). It will + have no effect on ephemeral volume types such as: secret, + configmaps and emptydir. Valid values are "OnRootMismatch" + and "Always". If not specified defaults to "Always".' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be set + in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run as a non-root + user. If true, the Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 (root) and fail + to start the container if it does. If unset or false, no + such validation will be performed. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container + process. Defaults to user specified in image metadata if + unspecified. May also be set in SecurityContext. If set + in both SecurityContext and PodSecurityContext, the value + specified in SecurityContext takes precedence for that container. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random + SELinux context for each container. May also be set in + SecurityContext. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. + properties: + localhostProfile: + description: localhostProfile indicates a profile defined + in a file on the node should be used. The profile must + be preconfigured on the node to work. Must be a descending + path, relative to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp profile + will be applied. Valid options are: \n Localhost - a + profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile + should be used. Unconfined - no profile should be applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first process + run in each container, in addition to the container's primary + GID. If unspecified, no groups will be added to any container. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls used + for the pod. Pods with unsupported sysctls (by the container + runtime) might fail to launch. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied to all + containers. If unspecified, the options within a container's + SecurityContext will be used. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission + webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential spec named + by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + runAsUserName: + description: The UserName in Windows to run the entrypoint + of the container process. Defaults to the user specified + in image metadata if unspecified. May also be set in + PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + type: object + serviceOptions: + description: Options to customize the services created for the Cryostat + application and Grafana dashboard. + properties: + coreConfig: + description: Specification for the service responsible for the + Cryostat application. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to add to the service during its + creation. + type: object + httpPort: + description: HTTP port number for the Cryostat application + service. Defaults to 8181. + format: int32 + type: integer + jmxPort: + description: Remote JMX port number for the Cryostat application + service. Defaults to 9091. + format: int32 + type: integer + labels: + additionalProperties: + type: string + description: Labels to add to the service during its creation. + The labels with keys "app" and "component" are reserved + for use by the operator. + type: object + serviceType: + description: Type of service to create. Defaults to "ClusterIP". + type: string + type: object + grafanaConfig: + description: Specification for the service responsible for the + Cryostat Grafana dashboard. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to add to the service during its + creation. + type: object + httpPort: + description: HTTP port number for the Grafana dashboard service. + Defaults to 3000. + format: int32 + type: integer + labels: + additionalProperties: + type: string + description: Labels to add to the service during its creation. + The labels with keys "app" and "component" are reserved + for use by the operator. + type: object + serviceType: + description: Type of service to create. Defaults to "ClusterIP". + type: string + type: object + reportsConfig: + description: Specification for the service responsible for the + cryostat-reports sidecars. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to add to the service during its + creation. + type: object + httpPort: + description: HTTP port number for the cryostat-reports service. + Defaults to 10000. + format: int32 + type: integer + labels: + additionalProperties: + type: string + description: Labels to add to the service during its creation. + The labels with keys "app" and "component" are reserved + for use by the operator. + type: object + serviceType: + description: Type of service to create. Defaults to "ClusterIP". + type: string + type: object + type: object + storageOptions: + description: Options to customize the storage for Flight Recordings + and Templates. + properties: + emptyDir: + description: Configuration for an EmptyDir to be created by the + operator instead of a PVC. + properties: + enabled: + description: When enabled, Cryostat will use EmptyDir volumes + instead of a Persistent Volume Claim. Any PVC configurations + will be ignored. + type: boolean + medium: + description: Unless specified, the emptyDir volume will be + mounted on the same storage medium backing the node. Setting + this field to "Memory" will mount the emptyDir on a tmpfs + (RAM-backed filesystem). + type: string + sizeLimit: + description: The maximum memory limit for the emptyDir. Default + is unbounded. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + type: string + type: object + pvc: + description: Configuration for the Persistent Volume Claim to + be created by the operator. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to add to the Persistent Volume Claim + during its creation. + type: object + labels: + additionalProperties: + type: string + description: Labels to add to the Persistent Volume Claim + during its creation. The label with key "app" is reserved + for use by the operator. + type: object + spec: + description: Spec for a Persistent Volume Claim, whose options + will override the defaults used by the operator. Unless + overriden, the PVC will be created with the default Storage + Class and 500MiB of storage. Once the operator has created + the PVC, changes to this field have no effect. + properties: + accessModes: + description: 'AccessModes contains the desired access + modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'This field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot + - Beta) * An existing PVC (PersistentVolumeClaim) * + An existing custom resource/object that implements data + population (Alpha) In order to use VolumeSnapshot object + types, the appropriate feature gate must be enabled + (VolumeSnapshotDataSource or AnyVolumeDataSource) If + the provisioner or an external controller can support + the specified data source, it will create a new volume + based on the contents of the specified data source. + If the specified data source is not supported, the volume + will not be created and the failure will be reported + as an event. In the future, we plan to support more + data source types and the behavior of the provisioner + may change.' + properties: + apiGroup: + description: APIGroup is the group for the resource + being referenced. If APIGroup is not specified, + the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + resources: + description: 'Resources represents the minimum resources + the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount + of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount + of compute resources required. If Requests is omitted + for a container, it defaults to Limits if that is + explicitly specified, otherwise to an implementation-defined + value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + type: object + selector: + description: A label query over volumes to consider for + binding. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values + array must be non-empty. If the operator is + Exists or DoesNotExist, the values array must + be empty. This array is replaced during a + strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + storageClassName: + description: 'Name of the StorageClass required by the + claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of volume is + required by the claim. Value of Filesystem is implied + when not included in claim spec. + type: string + volumeName: + description: VolumeName is the binding reference to the + PersistentVolume backing this claim. + type: string + type: object + type: object + type: object + targetDiscoveryOptions: + description: Options to configure the Cryostat application's target + discovery mechanisms. + properties: + builtInDiscoveryDisabled: + description: When true, the Cryostat application will disable + the built-in discovery mechanisms. Defaults to false + type: boolean + type: object + trustedCertSecrets: + description: List of TLS certificates to trust when connecting to + targets. + items: + properties: + certificateKey: + description: Key within secret containing the certificate. + type: string + secretName: + description: Name of secret in the local namespace. + type: string + required: + - secretName + type: object + type: array + required: + - minimal + type: object + status: + description: CryostatStatus defines the observed state of Cryostat. + properties: + applicationUrl: + description: Address of the deployed Cryostat web application. + type: string + conditions: + description: Conditions of the components managed by the Cryostat + Operator. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: + \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // +listMapKey=type + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + 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 + grafanaSecret: + description: Name of the Secret containing the generated Grafana credentials. + type: string + required: + - applicationUrl + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 9bbcc774b..a973a7d61 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -11,3 +11,6 @@ configMapGenerator: - files: - controller_manager_config.yaml name: manager-config +images: +- name: operator + newName: localhost:5001/infinispan-operator diff --git a/config/manifests/bases/infinispan-operator.clusterserviceversion.yaml b/config/manifests/bases/infinispan-operator.clusterserviceversion.yaml index 358c32cb8..19eac7a70 100644 --- a/config/manifests/bases/infinispan-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/infinispan-operator.clusterserviceversion.yaml @@ -110,6 +110,11 @@ spec: - urn:alm:descriptor:com.tectonic.ui:select:debug - urn:alm:descriptor:com.tectonic.ui:select:info - urn:alm:descriptor:com.tectonic.ui:select:error + - description: If true, a JMX endpoint is exposed on the admin service and a Cryostat CR is created to allow JFR recordings to be created via the UI + displayName: Toggle Cryostat + path: cryostat.enabled + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:booleanSwitch - description: The Persistent Volume Claim that holds custom libraries displayName: Persistent Volume Claim Name path: dependencies.volumeClaimName diff --git a/controllers/constants/constants.go b/controllers/constants/constants.go index 6fa9429e1..ad4642f52 100644 --- a/controllers/constants/constants.go +++ b/controllers/constants/constants.go @@ -49,10 +49,12 @@ const ( AdminPasswordKey = "password" InfinispanAdminPort = 11223 InfinispanAdminPortName = "infinispan-adm" - InfinispanUserPortName = "infinispan" + InfinispanJmxPort = 9999 + InfinispanJmxPortName = "jfr-jmx" // Cryostat constant required for automatic lookup of JMX endpoint InfinispanPingPort = 8888 InfinispanPingPortName = "ping" InfinispanUserPort = 11222 + InfinispanUserPortName = "infinispan" CrossSitePort = 7900 CrossSitePortName = "xsite" GossipRouterDiagPort = 7500 diff --git a/controllers/infinispan.go b/controllers/infinispan.go index de22265a4..e344c3b66 100644 --- a/controllers/infinispan.go +++ b/controllers/infinispan.go @@ -80,7 +80,7 @@ func (r *InfinispanReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Ma } r.supportedTypes = make(map[schema.GroupVersionKind]struct{}, 3) - for _, gvk := range []schema.GroupVersionKind{infinispan.IngressGVK, infinispan.RouteGVK, infinispan.ServiceMonitorGVK} { + for _, gvk := range []schema.GroupVersionKind{infinispan.IngressGVK, infinispan.RouteGVK, infinispan.ServiceMonitorGVK, infinispan.CryostatGVK} { // Validate that GroupVersionKind is supported on runtime platform ok, err := kubernetes.IsGroupVersionKindSupported(gvk) if err != nil { diff --git a/documentation/asciidoc/stories/assembly_monitoring.adoc b/documentation/asciidoc/stories/assembly_monitoring.adoc index e36915e7c..2d5e0a004 100644 --- a/documentation/asciidoc/stories/assembly_monitoring.adoc +++ b/documentation/asciidoc/stories/assembly_monitoring.adoc @@ -30,6 +30,8 @@ endif::downstream[] include::{topics}/proc_creating_grafana_datasources.adoc[leveloffset=+1] include::{topics}/proc_configuring_grafana_dashboards.adoc[leveloffset=+1] +include::{topics}/proc_deploying_cryostat.adoc[leveloffset=+1] + // Restore the parent context. ifdef::parent-context[:context: {parent-context}] ifndef::parent-context[:!context:] diff --git a/documentation/asciidoc/topics/attributes/community-attributes.adoc b/documentation/asciidoc/topics/attributes/community-attributes.adoc index e1031f0cd..6d31e1bd1 100644 --- a/documentation/asciidoc/topics/attributes/community-attributes.adoc +++ b/documentation/asciidoc/topics/attributes/community-attributes.adoc @@ -78,3 +78,5 @@ //Helm chart :helm_chart_docs: https://infinispan.org/docs/helm-chart/main/helm-chart.html + +:crystat_installation: https://cryostat.io/get-started/#installing-cryostat-operator[Installing Cryostat Operator] \ No newline at end of file diff --git a/documentation/asciidoc/topics/attributes/downstream-attributes.adoc b/documentation/asciidoc/topics/attributes/downstream-attributes.adoc index dec002abb..93740b742 100644 --- a/documentation/asciidoc/topics/attributes/downstream-attributes.adoc +++ b/documentation/asciidoc/topics/attributes/downstream-attributes.adoc @@ -22,3 +22,8 @@ // :kube_client: oc :native_cli: redhat-datagrid-cli + +// +// External links +// +:crystat_installation: https://access.redhat.com/documentation/en-us/red_hat_build_of_cryostat/2/html/installing_cryostat/index[Installing Cryostat] diff --git a/documentation/asciidoc/topics/proc_deploying_cryostat.adoc b/documentation/asciidoc/topics/proc_deploying_cryostat.adoc new file mode 100644 index 000000000..a126d4e15 --- /dev/null +++ b/documentation/asciidoc/topics/proc_deploying_cryostat.adoc @@ -0,0 +1,45 @@ +[id='deploying-cryostat_{context}'] += Setting up JFR recordings with Cryostat +Enable JDK Flight Recorder (JFR) monitoring for your {brandname} clusters that run on {k8s}. + +.JFR recordings with Cryostat +JFR provides insights into various aspects of JVM performance to ease cluster inspection and debugging. +Depending on your requirements, you can store and analyze your recordings using the integrated tools provided by Cryostat or export the recordings to an external monitoring application. + +When you enable Cryostat for {brandname} cluster, the following occurs: + +. Each {brandname} server pod exposes an authenticated JMX endpoint utilizing the "admin" security-realm, which includes the Operator user credentials. + +. {ispn_operator} creates a `Cryostat` CR in the cluster namespace. The Cryostat Operator then reconciles the CR to create a dedicated Cryostat instance for the {brandname} cluster. + +.Prerequisites + +* Install the Cryostat Operator. You can install the Cryostat Operator in your {k8s} project by using Operator Lifecycle Manager (OLM). + +.Procedure + +. Enable Cryostat in your `Infinispan` CR. ++ +[source,options="nowrap",subs=attributes+] +---- +include::yaml/infinispan-cryostat-enabled.yaml[] +---- + +. Wait for the `Cryostat` CR to be ready. ++ +[source,options="nowrap",subs=attributes+] +---- +{oc} wait -n --for=condition=MainDeploymentAvailable cryostat/test-cryostat-provisioning-cs +---- + +. Open the Cryostat application URL. ++ +[source,options="nowrap",subs=attributes+] +---- +{oc} -n get cryostat {example_crd_name}-cs +---- + +. Inspect {brandname} pods as required. + +.Additional resources +* link:{crystat_installation} diff --git a/documentation/asciidoc/topics/yaml/infinispan-cryostat-enabled.yaml b/documentation/asciidoc/topics/yaml/infinispan-cryostat-enabled.yaml new file mode 100644 index 000000000..64e0f0e30 --- /dev/null +++ b/documentation/asciidoc/topics/yaml/infinispan-cryostat-enabled.yaml @@ -0,0 +1,7 @@ +apiVersion: infinispan.org/v1 +kind: Infinispan +metadata: + name: {example_crd_name} +spec: + cryostat: + enabled: true diff --git a/launcher/operator/operator.go b/launcher/operator/operator.go index da861f30f..b498fef1c 100644 --- a/launcher/operator/operator.go +++ b/launcher/operator/operator.go @@ -7,6 +7,8 @@ import ( "strings" "github.com/infinispan/infinispan-operator/controllers" + cryostatv1beta1 "github.com/infinispan/infinispan-operator/pkg/apis/cryostat/v1beta1" + // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -44,6 +46,7 @@ func init() { utilruntime.Must(ingressv1.AddToScheme(scheme)) utilruntime.Must(monitoringv1.AddToScheme(scheme)) utilruntime.Must(grafanav1alpha1.AddToScheme(scheme)) + utilruntime.Must(cryostatv1beta1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } diff --git a/pkg/apis/cryostat/v1beta1/cryostat_types.go b/pkg/apis/cryostat/v1beta1/cryostat_types.go new file mode 100644 index 000000000..fe5624815 --- /dev/null +++ b/pkg/apis/cryostat/v1beta1/cryostat_types.go @@ -0,0 +1,531 @@ +// Copyright The Cryostat Authors +// +// The Universal Permissive License (UPL), Version 1.0 +// +// Subject to the condition set forth below, permission is hereby granted to any +// person obtaining a copy of this software, associated documentation and/or data +// (collectively the "Software"), free of charge and under any and all copyright +// rights in the Software, and any and all patent rights owned or freely +// licensable by each licensor hereunder covering either (i) the unmodified +// Software as contributed to or provided by such licensor, or (ii) the Larger +// Works (as defined below), to deal in both +// +// (a) the Software, and +// (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +// one is included with the Software (each a "Larger Work" to which the Software +// is contributed by such licensors), +// +// without restriction, including without limitation the rights to copy, create +// derivative works of, display, perform, and distribute the Software and make, +// use, sell, offer for sale, import, export, have made, and have sold the +// Software and the Larger Work(s), and to sublicense the foregoing rights on +// either these or other terms. +// +// This license is subject to the following condition: +// The above copyright notice and either this complete permission notice or at +// a minimum a reference to the UPL must be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + netv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// CryostatSpec defines the desired state of Cryostat. +type CryostatSpec struct { + // Deploy a pared-down Cryostat instance with no Grafana Dashboard or JFR Data Source. + // +operator-sdk:csv:customresourcedefinitions:type=spec,order=4,displayName="Minimal Deployment",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"} + Minimal bool `json:"minimal"` + // List of TLS certificates to trust when connecting to targets. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Trusted TLS Certificates" + TrustedCertSecrets []CertificateSecret `json:"trustedCertSecrets,omitempty"` + // List of Flight Recorder Event Templates to preconfigure in Cryostat. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Event Templates" + EventTemplates []TemplateConfigMap `json:"eventTemplates,omitempty"` + // Use cert-manager to secure in-cluster communication between Cryostat components. + // Requires cert-manager to be installed. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,order=3,displayName="Enable cert-manager Integration",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"} + EnableCertManager *bool `json:"enableCertManager"` + // Options to customize the storage for Flight Recordings and Templates. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + StorageOptions *StorageConfiguration `json:"storageOptions,omitempty"` + // Options to customize the services created for the Cryostat application and Grafana dashboard. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + ServiceOptions *ServiceConfigList `json:"serviceOptions,omitempty"` + // Options to control how the operator exposes the application outside of the cluster, + // such as using an Ingress or Route. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + NetworkOptions *NetworkConfigurationList `json:"networkOptions,omitempty"` + // Options to configure Cryostat Automated Report Analysis. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + ReportOptions *ReportConfiguration `json:"reportOptions,omitempty"` + // The maximum number of WebSocket client connections allowed (minimum 1, default unlimited). + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Max WebSocket Connections",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:number"} + // +kubebuilder:validation:Minimum=1 + MaxWsConnections int32 `json:"maxWsConnections,omitempty"` + // Options to customize the JMX target connections cache for the Cryostat application. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="JMX Connections Cache Options" + JmxCacheOptions *JmxCacheOptions `json:"jmxCacheOptions,omitempty"` + // Resource requirements for the Cryostat deployment. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + Resources *ResourceConfigList `json:"resources,omitempty"` + // Override default authorization properties for Cryostat on OpenShift. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Authorization Properties",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"} + AuthProperties *AuthorizationProperties `json:"authProperties,omitempty"` + // Options to configure the Security Contexts for the Cryostat application. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"} + SecurityOptions *SecurityOptions `json:"securityOptions,omitempty"` + // Options to configure scheduling for the Cryostat deployment + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + SchedulingOptions *SchedulingConfiguration `json:"schedulingOptions,omitempty"` + // Options to configure the Cryostat application's target discovery mechanisms. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + TargetDiscoveryOptions *TargetDiscoveryOptions `json:"targetDiscoveryOptions,omitempty"` + // Options to configure the Cryostat application's credentials database. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Credentials Database Options" + JmxCredentialsDatabaseOptions *JmxCredentialsDatabaseOptions `json:"jmxCredentialsDatabaseOptions,omitempty"` +} + +type ResourceConfigList struct { + // Resource requirements for the Cryostat application. If specifying a memory limit, at least 768MiB is recommended. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:resourceRequirements"} + CoreResources corev1.ResourceRequirements `json:"coreResources,omitempty"` + // Resource requirements for the JFR Data Source container. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:resourceRequirements"} + DataSourceResources corev1.ResourceRequirements `json:"dataSourceResources,omitempty"` + // Resource requirements for the Grafana container. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:resourceRequirements"} + GrafanaResources corev1.ResourceRequirements `json:"grafanaResources,omitempty"` +} + +// CryostatStatus defines the observed state of Cryostat. +type CryostatStatus struct { + // Conditions of the components managed by the Cryostat Operator. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status,displayName="Cryostat Conditions",xDescriptors={"urn:alm:descriptor:io.kubernetes.conditions"} + Conditions []metav1.Condition `json:"conditions,omitempty"` + // Name of the Secret containing the generated Grafana credentials. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=status,order=2,xDescriptors={"urn:alm:descriptor:io.kubernetes:Secret"} + GrafanaSecret string `json:"grafanaSecret,omitempty"` + // Address of the deployed Cryostat web application. + // +operator-sdk:csv:customresourcedefinitions:type=status,order=1,xDescriptors={"urn:alm:descriptor:org.w3:link"} + ApplicationURL string `json:"applicationUrl"` +} + +// CryostatConditionType refers to a Condition type that may be used in status.conditions +type CryostatConditionType string + +const ( + // Whether the main Cryostat deployment is available. + ConditionTypeMainDeploymentAvailable CryostatConditionType = "MainDeploymentAvailable" + // Whether the main Cryostat deployment is progressing. + ConditionTypeMainDeploymentProgressing CryostatConditionType = "MainDeploymentProgressing" + // If pods within the main Cryostat deployment failed to be created or destroyed. + ConditionTypeMainDeploymentReplicaFailure CryostatConditionType = "MainDeploymentReplicaFailure" + // If enabled, whether the reports deployment is available. + ConditionTypeReportsDeploymentAvailable CryostatConditionType = "ReportsDeploymentAvailable" + // If enabled, whether the reports deployment is progressing. + ConditionTypeReportsDeploymentProgressing CryostatConditionType = "ReportsDeploymentProgressing" + // If enabled, whether pods in the reports deployment failed to be created or destroyed. + ConditionTypeReportsDeploymentReplicaFailure CryostatConditionType = "ReportsDeploymentReplicaFailure" + // If enabled, whether TLS setup is complete for the Cryostat components. + ConditionTypeTLSSetupComplete CryostatConditionType = "TLSSetupComplete" +) + +// StorageConfiguration provides customization to the storage created by +// the operator to hold Flight Recordings and Recording Templates. If no +// configurations are specified, a PVC will be created by default. +type StorageConfiguration struct { + // Configuration for the Persistent Volume Claim to be created + // by the operator. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + PVC *PersistentVolumeClaimConfig `json:"pvc,omitempty"` + // Configuration for an EmptyDir to be created + // by the operator instead of a PVC. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + EmptyDir *EmptyDirConfig `json:"emptyDir,omitempty"` +} + +// ReportConfiguration is used to determine how many replicas of cryostat-reports +// the operator should create and what the resource limits of those containers +// should be. If no replicas are created then Cryostat is configured to use basic +// subprocess report generation. If at least one replica is created then Cryostat +// is configured to use remote report generation, pointed at a load balancer service +// in front of the cryostat-reports replicas. +type ReportConfiguration struct { + // The number of report sidecar replica containers to deploy. + // Each replica can service one report generation request at a time. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:podCount"} + Replicas int32 `json:"replicas,omitempty"` + // The resources allocated to each sidecar replica. + // A replica with more resources can handle larger input recordings and will process them faster. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:resourceRequirements"} + Resources corev1.ResourceRequirements `json:"resources,omitempty"` + // When zero report sidecar replicas are requested, SubProcessMaxHeapSize configures + // the maximum heap size of the basic subprocess report generator in MiB. + // The default heap size is `200` (MiB). + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:number"} + SubProcessMaxHeapSize int32 `json:"subProcessMaxHeapSize,omitempty"` + // Options to configure the Security Contexts for the Cryostat report generator. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:advanced"} + SecurityOptions *ReportsSecurityOptions `json:"securityOptions,omitempty"` + // Options to configure scheduling for the reports deployment + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + SchedulingOptions *SchedulingConfiguration `json:"schedulingOptions,omitempty"` +} + +// SchedulingConfiguration contains multiple choices to control scheduling of Cryostat pods +type SchedulingConfiguration struct { + // Label selector used to schedule a Cryostat pod to a node. See: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:selector:core:v1:Node"} + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + // Affinity rules for scheduling Cryostat pods. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + Affinity *Affinity `json:"affinity,omitempty"` + // Tolerations to allow scheduling of Cryostat pods to tainted nodes. See: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` +} + +// Affinity groups different kinds of affinity configurations for Cryostat pods +type Affinity struct { + // Node affinity scheduling rules for a Cryostat pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#NodeAffinity + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:nodeAffinity"} + NodeAffinity *corev1.NodeAffinity `json:"nodeAffinity,omitempty"` + // Pod affinity scheduling rules for a Cryostat pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodAffinity + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:podAffinity"} + PodAffinity *corev1.PodAffinity `json:"podAffinity,omitempty"` + // Pod anti-affinity scheduling rules for a Cryostat pod. See: https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#PodAntiAffinity + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:podAntiAffinity"} + PodAntiAffinity *corev1.PodAntiAffinity `json:"podAntiAffinity,omitempty"` +} + +// ServiceConfig provides customization for a service created +// by the operator. +type ServiceConfig struct { + // Type of service to create. Defaults to "ClusterIP". + // +optional + ServiceType *corev1.ServiceType `json:"serviceType,omitempty"` + // Annotations to add to the service during its creation. + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + // Labels to add to the service during its creation. + // The labels with keys "app" and "component" are reserved + // for use by the operator. + // +optional + Labels map[string]string `json:"labels,omitempty"` +} + +// CoreServiceConfig provides customization for the service handling +// traffic for the Cryostat application. +type CoreServiceConfig struct { + // HTTP port number for the Cryostat application service. + // Defaults to 8181. + // +optional + HTTPPort *int32 `json:"httpPort,omitempty"` + // Remote JMX port number for the Cryostat application service. + // Defaults to 9091. + // +optional + JMXPort *int32 `json:"jmxPort,omitempty"` + ServiceConfig `json:",inline"` +} + +// GrafanaServiceConfig provides customization for the service handling +// traffic for the Grafana dashboard. +type GrafanaServiceConfig struct { + // HTTP port number for the Grafana dashboard service. + // Defaults to 3000. + // +optional + HTTPPort *int32 `json:"httpPort,omitempty"` + ServiceConfig `json:",inline"` +} + +// ReportsServiceConfig provides customization for the service handling +// traffic for the cryostat-reports sidecars. +type ReportsServiceConfig struct { + // HTTP port number for the cryostat-reports service. + // Defaults to 10000. + // +optional + HTTPPort *int32 `json:"httpPort,omitempty"` + ServiceConfig `json:",inline"` +} + +// ServiceConfigList holds the service configuration for each +// service created by the operator. +type ServiceConfigList struct { + // Specification for the service responsible for the Cryostat application. + // +optional + CoreConfig *CoreServiceConfig `json:"coreConfig,omitempty"` + // Specification for the service responsible for the Cryostat Grafana dashboard. + // +optional + GrafanaConfig *GrafanaServiceConfig `json:"grafanaConfig,omitempty"` + // Specification for the service responsible for the cryostat-reports sidecars. + // +optional + ReportsConfig *ReportsServiceConfig `json:"reportsConfig,omitempty"` +} + +// NetworkConfiguration provides customization for how to expose a Cryostat +// service, so that it can be reached from outside the cluster. +// On OpenShift, a Route is created by default. On Kubernetes, an Ingress will +// be created if the IngressSpec is defined within this NetworkConfiguration. +type NetworkConfiguration struct { + // Configuration for an Ingress object. + // Currently subpaths are not supported, so unique hosts must be specified + // (if a single external IP is being used) to differentiate between ingresses/services. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + IngressSpec *netv1.IngressSpec `json:"ingressSpec,omitempty"` + // Annotations to add to the Ingress or Route during its creation. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + Annotations map[string]string `json:"annotations,omitempty"` + // Labels to add to the Ingress or Route during its creation. + // The label with key "app" is reserved for use by the operator. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + Labels map[string]string `json:"labels,omitempty"` +} + +// NetworkConfigurationList holds NetworkConfiguration objects that specify +// how to expose the services created by the operator for the main Cryostat +// deployment. +type NetworkConfigurationList struct { + // Specifications for how to expose the Cryostat service, + // which serves the Cryostat application. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + CoreConfig *NetworkConfiguration `json:"coreConfig,omitempty"` + // Specifications for how to expose the Cryostat command service, + // which serves the WebSocket command channel. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:hidden"} + // + // Deprecated: CommandConfig is no longer used. + CommandConfig *NetworkConfiguration `json:"commandConfig,omitempty"` + // Specifications for how to expose Cryostat's Grafana service, + // which serves the Grafana dashboard. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + GrafanaConfig *NetworkConfiguration `json:"grafanaConfig,omitempty"` +} + +// PersistentVolumeClaimConfig holds all customization options to +// configure a Persistent Volume Claim to be created and managed +// by the operator. +type PersistentVolumeClaimConfig struct { + // Annotations to add to the Persistent Volume Claim during its creation. + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + // Labels to add to the Persistent Volume Claim during its creation. + // The label with key "app" is reserved for use by the operator. + // +optional + Labels map[string]string `json:"labels,omitempty"` + // Spec for a Persistent Volume Claim, whose options will override the + // defaults used by the operator. Unless overriden, the PVC will be + // created with the default Storage Class and 500MiB of storage. + // Once the operator has created the PVC, changes to this field have + // no effect. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + Spec *corev1.PersistentVolumeClaimSpec `json:"spec,omitempty"` +} + +// EmptyDirConfig holds all customization options to +// configure an EmptyDir to be created and managed +// by the operator. +type EmptyDirConfig struct { + // When enabled, Cryostat will use EmptyDir volumes instead of a Persistent Volume Claim. Any PVC configurations will be ignored. + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"} + Enabled bool `json:"enabled,omitempty"` + // Unless specified, the emptyDir volume will be mounted on + // the same storage medium backing the node. Setting this field to + // "Memory" will mount the emptyDir on a tmpfs (RAM-backed filesystem). + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldDependency:storageOptions.emptyDir.enabled:true"} + Medium corev1.StorageMedium `json:"medium,omitempty"` + // The maximum memory limit for the emptyDir. Default is unbounded. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:fieldDependency:storageOptions.emptyDir.enabled:true"} + // +kubebuilder:validation:Pattern=^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + SizeLimit string `json:"sizeLimit,omitempty"` +} + +// JmxCacheConfig provides customization for the JMX target connections +// cache for the Cryostat application. +type JmxCacheOptions struct { + // The maximum number of JMX connections to cache. Use `-1` for an unlimited cache size (TTL expiration only). Defaults to `-1`. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:number"} + // +kubebuilder:validation:Minimum=-1 + TargetCacheSize int32 `json:"targetCacheSize,omitempty"` + // The time to live (in seconds) for cached JMX connections. Defaults to `10`. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:number"} + // +kubebuilder:validation:Minimum=1 + TargetCacheTTL int32 `json:"targetCacheTTL,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +kubebuilder:resource:path=cryostats,scope=Namespaced + +// Cryostat allows you to install Cryostat for a single namespace. +// It contains configuration options for controlling the Deployment of the Cryostat +// application and its related components. +// A ClusterCryostat or Cryostat instance must be created to instruct the operator +// to deploy the Cryostat application. +// +operator-sdk:csv:customresourcedefinitions:resources={{Deployment,v1},{Ingress,v1},{PersistentVolumeClaim,v1},{Secret,v1},{Service,v1},{Route,v1},{ConsoleLink,v1}} +// +kubebuilder:printcolumn:name="Application URL",type=string,JSONPath=`.status.applicationUrl` +// +kubebuilder:printcolumn:name="Grafana Secret",type=string,JSONPath=`.status.grafanaSecret` +type Cryostat struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CryostatSpec `json:"spec,omitempty"` + Status CryostatStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// CryostatList contains a list of Cryostat +type CryostatList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Cryostat `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Cryostat{}, &CryostatList{}) +} + +// DefaultCertificateKey will be used when looking up the certificate within a secret, +// if a key is not manually specified. +const DefaultCertificateKey = corev1.TLSCertKey + +type CertificateSecret struct { + // Name of secret in the local namespace. + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:io.kubernetes:Secret"} + SecretName string `json:"secretName"` + // Key within secret containing the certificate. + // +optional + CertificateKey *string `json:"certificateKey,omitempty"` +} + +// A ConfigMap containing a .jfc template file. +type TemplateConfigMap struct { + // Name of config map in the local namespace. + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:io.kubernetes:ConfigMap"} + ConfigMapName string `json:"configMapName"` + // Filename within config map containing the template file. + Filename string `json:"filename"` +} + +// Authorization properties provide custom permission mapping between Cryostat resources to Kubernetes resources. +// If the mapping is updated, Cryostat must be manually restarted. +type AuthorizationProperties struct { + // Name of the ClusterRole to use when Cryostat requests a role-scoped OAuth token. + // This ClusterRole should contain permissions for all Kubernetes objects listed in custom permission mapping. + // More details: https://docs.openshift.com/container-platform/4.11/authentication/tokens-scoping.html#scoping-tokens-role-scope_configuring-internal-oauth + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="ClusterRole Name",xDescriptors={"urn:alm:descriptor:io.kubernetes:ClusterRole"} + ClusterRoleName string `json:"clusterRoleName"` + // Name of config map in the local namespace. + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="ConfigMap Name",xDescriptors={"urn:alm:descriptor:io.kubernetes:ConfigMap"} + ConfigMapName string `json:"configMapName"` + // Filename within config map containing the resource mapping. + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:com.tectonic.ui:text"} + Filename string `json:"filename"` +} + +// SecurityOptions contains Security Context customizations for the +// main Cryostat application at both the pod and container level. +type SecurityOptions struct { + // Security Context to apply to the Cryostat pod. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + // Security Context to apply to the Cryostat application container. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + CoreSecurityContext *corev1.SecurityContext `json:"coreSecurityContext,omitempty"` + // Security Context to apply to the JFR Data Source container. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + DataSourceSecurityContext *corev1.SecurityContext `json:"dataSourceSecurityContext,omitempty"` + // Security Context to apply to the Grafana container. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + GrafanaSecurityContext *corev1.SecurityContext `json:"grafanaSecurityContext,omitempty"` +} + +// ReportsSecurityOptions contains Security Context customizations for the +// Cryostat report generator at both the pod and container level. +type ReportsSecurityOptions struct { + // Security Context to apply to the Cryostat report generator pod. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + // Security Context to apply to the Cryostat report generator container. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec + ReportsSecurityContext *corev1.SecurityContext `json:"reportsSecurityContext,omitempty"` +} + +// TargetDiscoveryOptions provides configuration options to the Cryostat application's target discovery mechanisms. +type TargetDiscoveryOptions struct { + // When true, the Cryostat application will disable the built-in discovery mechanisms. Defaults to false + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Disable Built-in Discovery",xDescriptors={"urn:alm:descriptor:com.tectonic.ui:booleanSwitch"} + BuiltInDiscoveryDisabled bool `json:"builtInDiscoveryDisabled,omitempty"` +} + +// JmxCredentialsDatabaseOptions provides configuration options to the Cryostat application's credentials database. +type JmxCredentialsDatabaseOptions struct { + // Name of the secret containing the password to encrypt credentials database. + // +optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:io.kubernetes:Secret"} + DatabaseSecretName *string `json:"databaseSecretName,omitempty"` +} diff --git a/pkg/apis/cryostat/v1beta1/groupversion_info.go b/pkg/apis/cryostat/v1beta1/groupversion_info.go new file mode 100644 index 000000000..0b18daf53 --- /dev/null +++ b/pkg/apis/cryostat/v1beta1/groupversion_info.go @@ -0,0 +1,56 @@ +// Copyright The Cryostat Authors +// +// The Universal Permissive License (UPL), Version 1.0 +// +// Subject to the condition set forth below, permission is hereby granted to any +// person obtaining a copy of this software, associated documentation and/or data +// (collectively the "Software"), free of charge and under any and all copyright +// rights in the Software, and any and all patent rights owned or freely +// licensable by each licensor hereunder covering either (i) the unmodified +// Software as contributed to or provided by such licensor, or (ii) the Larger +// Works (as defined below), to deal in both +// +// (a) the Software, and +// (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +// one is included with the Software (each a "Larger Work" to which the Software +// is contributed by such licensors), +// +// without restriction, including without limitation the rights to copy, create +// derivative works of, display, perform, and distribute the Software and make, +// use, sell, offer for sale, import, export, have made, and have sold the +// Software and the Larger Work(s), and to sublicense the foregoing rights on +// either these or other terms. +// +// This license is subject to the following condition: +// The above copyright notice and either this complete permission notice or at +// a minimum a reference to the UPL must be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +// Package v1beta1 contains API Schema definitions for the operator v1beta1 API group +// +kubebuilder:object:generate=true +// +groupName=operator.cryostat.io +package v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "operator.cryostat.io", Version: "v1beta1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/pkg/apis/cryostat/v1beta1/zz_generated.deepcopy.go b/pkg/apis/cryostat/v1beta1/zz_generated.deepcopy.go new file mode 100644 index 000000000..79858f578 --- /dev/null +++ b/pkg/apis/cryostat/v1beta1/zz_generated.deepcopy.go @@ -0,0 +1,719 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code generated by controller-gen. DO NOT EDIT. + +package v1beta1 + +import ( + corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Affinity) DeepCopyInto(out *Affinity) { + *out = *in + if in.NodeAffinity != nil { + in, out := &in.NodeAffinity, &out.NodeAffinity + *out = new(corev1.NodeAffinity) + (*in).DeepCopyInto(*out) + } + if in.PodAffinity != nil { + in, out := &in.PodAffinity, &out.PodAffinity + *out = new(corev1.PodAffinity) + (*in).DeepCopyInto(*out) + } + if in.PodAntiAffinity != nil { + in, out := &in.PodAntiAffinity, &out.PodAntiAffinity + *out = new(corev1.PodAntiAffinity) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Affinity. +func (in *Affinity) DeepCopy() *Affinity { + if in == nil { + return nil + } + out := new(Affinity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthorizationProperties) DeepCopyInto(out *AuthorizationProperties) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizationProperties. +func (in *AuthorizationProperties) DeepCopy() *AuthorizationProperties { + if in == nil { + return nil + } + out := new(AuthorizationProperties) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CertificateSecret) DeepCopyInto(out *CertificateSecret) { + *out = *in + if in.CertificateKey != nil { + in, out := &in.CertificateKey, &out.CertificateKey + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CertificateSecret. +func (in *CertificateSecret) DeepCopy() *CertificateSecret { + if in == nil { + return nil + } + out := new(CertificateSecret) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CoreServiceConfig) DeepCopyInto(out *CoreServiceConfig) { + *out = *in + if in.HTTPPort != nil { + in, out := &in.HTTPPort, &out.HTTPPort + *out = new(int32) + **out = **in + } + if in.JMXPort != nil { + in, out := &in.JMXPort, &out.JMXPort + *out = new(int32) + **out = **in + } + in.ServiceConfig.DeepCopyInto(&out.ServiceConfig) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CoreServiceConfig. +func (in *CoreServiceConfig) DeepCopy() *CoreServiceConfig { + if in == nil { + return nil + } + out := new(CoreServiceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cryostat) DeepCopyInto(out *Cryostat) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cryostat. +func (in *Cryostat) DeepCopy() *Cryostat { + if in == nil { + return nil + } + out := new(Cryostat) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Cryostat) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CryostatList) DeepCopyInto(out *CryostatList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Cryostat, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CryostatList. +func (in *CryostatList) DeepCopy() *CryostatList { + if in == nil { + return nil + } + out := new(CryostatList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CryostatList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CryostatSpec) DeepCopyInto(out *CryostatSpec) { + *out = *in + if in.TrustedCertSecrets != nil { + in, out := &in.TrustedCertSecrets, &out.TrustedCertSecrets + *out = make([]CertificateSecret, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EventTemplates != nil { + in, out := &in.EventTemplates, &out.EventTemplates + *out = make([]TemplateConfigMap, len(*in)) + copy(*out, *in) + } + if in.EnableCertManager != nil { + in, out := &in.EnableCertManager, &out.EnableCertManager + *out = new(bool) + **out = **in + } + if in.StorageOptions != nil { + in, out := &in.StorageOptions, &out.StorageOptions + *out = new(StorageConfiguration) + (*in).DeepCopyInto(*out) + } + if in.ServiceOptions != nil { + in, out := &in.ServiceOptions, &out.ServiceOptions + *out = new(ServiceConfigList) + (*in).DeepCopyInto(*out) + } + if in.NetworkOptions != nil { + in, out := &in.NetworkOptions, &out.NetworkOptions + *out = new(NetworkConfigurationList) + (*in).DeepCopyInto(*out) + } + if in.ReportOptions != nil { + in, out := &in.ReportOptions, &out.ReportOptions + *out = new(ReportConfiguration) + (*in).DeepCopyInto(*out) + } + if in.JmxCacheOptions != nil { + in, out := &in.JmxCacheOptions, &out.JmxCacheOptions + *out = new(JmxCacheOptions) + **out = **in + } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new(ResourceConfigList) + (*in).DeepCopyInto(*out) + } + if in.AuthProperties != nil { + in, out := &in.AuthProperties, &out.AuthProperties + *out = new(AuthorizationProperties) + **out = **in + } + if in.SecurityOptions != nil { + in, out := &in.SecurityOptions, &out.SecurityOptions + *out = new(SecurityOptions) + (*in).DeepCopyInto(*out) + } + if in.SchedulingOptions != nil { + in, out := &in.SchedulingOptions, &out.SchedulingOptions + *out = new(SchedulingConfiguration) + (*in).DeepCopyInto(*out) + } + if in.TargetDiscoveryOptions != nil { + in, out := &in.TargetDiscoveryOptions, &out.TargetDiscoveryOptions + *out = new(TargetDiscoveryOptions) + **out = **in + } + if in.JmxCredentialsDatabaseOptions != nil { + in, out := &in.JmxCredentialsDatabaseOptions, &out.JmxCredentialsDatabaseOptions + *out = new(JmxCredentialsDatabaseOptions) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CryostatSpec. +func (in *CryostatSpec) DeepCopy() *CryostatSpec { + if in == nil { + return nil + } + out := new(CryostatSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CryostatStatus) DeepCopyInto(out *CryostatStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CryostatStatus. +func (in *CryostatStatus) DeepCopy() *CryostatStatus { + if in == nil { + return nil + } + out := new(CryostatStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EmptyDirConfig) DeepCopyInto(out *EmptyDirConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmptyDirConfig. +func (in *EmptyDirConfig) DeepCopy() *EmptyDirConfig { + if in == nil { + return nil + } + out := new(EmptyDirConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GrafanaServiceConfig) DeepCopyInto(out *GrafanaServiceConfig) { + *out = *in + if in.HTTPPort != nil { + in, out := &in.HTTPPort, &out.HTTPPort + *out = new(int32) + **out = **in + } + in.ServiceConfig.DeepCopyInto(&out.ServiceConfig) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GrafanaServiceConfig. +func (in *GrafanaServiceConfig) DeepCopy() *GrafanaServiceConfig { + if in == nil { + return nil + } + out := new(GrafanaServiceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JmxCacheOptions) DeepCopyInto(out *JmxCacheOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JmxCacheOptions. +func (in *JmxCacheOptions) DeepCopy() *JmxCacheOptions { + if in == nil { + return nil + } + out := new(JmxCacheOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JmxCredentialsDatabaseOptions) DeepCopyInto(out *JmxCredentialsDatabaseOptions) { + *out = *in + if in.DatabaseSecretName != nil { + in, out := &in.DatabaseSecretName, &out.DatabaseSecretName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JmxCredentialsDatabaseOptions. +func (in *JmxCredentialsDatabaseOptions) DeepCopy() *JmxCredentialsDatabaseOptions { + if in == nil { + return nil + } + out := new(JmxCredentialsDatabaseOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkConfiguration) DeepCopyInto(out *NetworkConfiguration) { + *out = *in + if in.IngressSpec != nil { + in, out := &in.IngressSpec, &out.IngressSpec + *out = new(networkingv1.IngressSpec) + (*in).DeepCopyInto(*out) + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkConfiguration. +func (in *NetworkConfiguration) DeepCopy() *NetworkConfiguration { + if in == nil { + return nil + } + out := new(NetworkConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NetworkConfigurationList) DeepCopyInto(out *NetworkConfigurationList) { + *out = *in + if in.CoreConfig != nil { + in, out := &in.CoreConfig, &out.CoreConfig + *out = new(NetworkConfiguration) + (*in).DeepCopyInto(*out) + } + if in.CommandConfig != nil { + in, out := &in.CommandConfig, &out.CommandConfig + *out = new(NetworkConfiguration) + (*in).DeepCopyInto(*out) + } + if in.GrafanaConfig != nil { + in, out := &in.GrafanaConfig, &out.GrafanaConfig + *out = new(NetworkConfiguration) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkConfigurationList. +func (in *NetworkConfigurationList) DeepCopy() *NetworkConfigurationList { + if in == nil { + return nil + } + out := new(NetworkConfigurationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentVolumeClaimConfig) DeepCopyInto(out *PersistentVolumeClaimConfig) { + *out = *in + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(corev1.PersistentVolumeClaimSpec) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimConfig. +func (in *PersistentVolumeClaimConfig) DeepCopy() *PersistentVolumeClaimConfig { + if in == nil { + return nil + } + out := new(PersistentVolumeClaimConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReportConfiguration) DeepCopyInto(out *ReportConfiguration) { + *out = *in + in.Resources.DeepCopyInto(&out.Resources) + if in.SecurityOptions != nil { + in, out := &in.SecurityOptions, &out.SecurityOptions + *out = new(ReportsSecurityOptions) + (*in).DeepCopyInto(*out) + } + if in.SchedulingOptions != nil { + in, out := &in.SchedulingOptions, &out.SchedulingOptions + *out = new(SchedulingConfiguration) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReportConfiguration. +func (in *ReportConfiguration) DeepCopy() *ReportConfiguration { + if in == nil { + return nil + } + out := new(ReportConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReportsSecurityOptions) DeepCopyInto(out *ReportsSecurityOptions) { + *out = *in + if in.PodSecurityContext != nil { + in, out := &in.PodSecurityContext, &out.PodSecurityContext + *out = new(corev1.PodSecurityContext) + (*in).DeepCopyInto(*out) + } + if in.ReportsSecurityContext != nil { + in, out := &in.ReportsSecurityContext, &out.ReportsSecurityContext + *out = new(corev1.SecurityContext) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReportsSecurityOptions. +func (in *ReportsSecurityOptions) DeepCopy() *ReportsSecurityOptions { + if in == nil { + return nil + } + out := new(ReportsSecurityOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReportsServiceConfig) DeepCopyInto(out *ReportsServiceConfig) { + *out = *in + if in.HTTPPort != nil { + in, out := &in.HTTPPort, &out.HTTPPort + *out = new(int32) + **out = **in + } + in.ServiceConfig.DeepCopyInto(&out.ServiceConfig) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReportsServiceConfig. +func (in *ReportsServiceConfig) DeepCopy() *ReportsServiceConfig { + if in == nil { + return nil + } + out := new(ReportsServiceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceConfigList) DeepCopyInto(out *ResourceConfigList) { + *out = *in + in.CoreResources.DeepCopyInto(&out.CoreResources) + in.DataSourceResources.DeepCopyInto(&out.DataSourceResources) + in.GrafanaResources.DeepCopyInto(&out.GrafanaResources) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceConfigList. +func (in *ResourceConfigList) DeepCopy() *ResourceConfigList { + if in == nil { + return nil + } + out := new(ResourceConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SchedulingConfiguration) DeepCopyInto(out *SchedulingConfiguration) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(Affinity) + (*in).DeepCopyInto(*out) + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]corev1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchedulingConfiguration. +func (in *SchedulingConfiguration) DeepCopy() *SchedulingConfiguration { + if in == nil { + return nil + } + out := new(SchedulingConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SecurityOptions) DeepCopyInto(out *SecurityOptions) { + *out = *in + if in.PodSecurityContext != nil { + in, out := &in.PodSecurityContext, &out.PodSecurityContext + *out = new(corev1.PodSecurityContext) + (*in).DeepCopyInto(*out) + } + if in.CoreSecurityContext != nil { + in, out := &in.CoreSecurityContext, &out.CoreSecurityContext + *out = new(corev1.SecurityContext) + (*in).DeepCopyInto(*out) + } + if in.DataSourceSecurityContext != nil { + in, out := &in.DataSourceSecurityContext, &out.DataSourceSecurityContext + *out = new(corev1.SecurityContext) + (*in).DeepCopyInto(*out) + } + if in.GrafanaSecurityContext != nil { + in, out := &in.GrafanaSecurityContext, &out.GrafanaSecurityContext + *out = new(corev1.SecurityContext) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityOptions. +func (in *SecurityOptions) DeepCopy() *SecurityOptions { + if in == nil { + return nil + } + out := new(SecurityOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceConfig) DeepCopyInto(out *ServiceConfig) { + *out = *in + if in.ServiceType != nil { + in, out := &in.ServiceType, &out.ServiceType + *out = new(corev1.ServiceType) + **out = **in + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceConfig. +func (in *ServiceConfig) DeepCopy() *ServiceConfig { + if in == nil { + return nil + } + out := new(ServiceConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ServiceConfigList) DeepCopyInto(out *ServiceConfigList) { + *out = *in + if in.CoreConfig != nil { + in, out := &in.CoreConfig, &out.CoreConfig + *out = new(CoreServiceConfig) + (*in).DeepCopyInto(*out) + } + if in.GrafanaConfig != nil { + in, out := &in.GrafanaConfig, &out.GrafanaConfig + *out = new(GrafanaServiceConfig) + (*in).DeepCopyInto(*out) + } + if in.ReportsConfig != nil { + in, out := &in.ReportsConfig, &out.ReportsConfig + *out = new(ReportsServiceConfig) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceConfigList. +func (in *ServiceConfigList) DeepCopy() *ServiceConfigList { + if in == nil { + return nil + } + out := new(ServiceConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StorageConfiguration) DeepCopyInto(out *StorageConfiguration) { + *out = *in + if in.PVC != nil { + in, out := &in.PVC, &out.PVC + *out = new(PersistentVolumeClaimConfig) + (*in).DeepCopyInto(*out) + } + if in.EmptyDir != nil { + in, out := &in.EmptyDir, &out.EmptyDir + *out = new(EmptyDirConfig) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageConfiguration. +func (in *StorageConfiguration) DeepCopy() *StorageConfiguration { + if in == nil { + return nil + } + out := new(StorageConfiguration) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetDiscoveryOptions) DeepCopyInto(out *TargetDiscoveryOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetDiscoveryOptions. +func (in *TargetDiscoveryOptions) DeepCopy() *TargetDiscoveryOptions { + if in == nil { + return nil + } + out := new(TargetDiscoveryOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TemplateConfigMap) DeepCopyInto(out *TemplateConfigMap) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateConfigMap. +func (in *TemplateConfigMap) DeepCopy() *TemplateConfigMap { + if in == nil { + return nil + } + out := new(TemplateConfigMap) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/http/client.go b/pkg/http/client.go index 0943555f0..0b8940b13 100644 --- a/pkg/http/client.go +++ b/pkg/http/client.go @@ -15,6 +15,7 @@ type HttpClient interface { Head(path string, headers map[string]string) (*http.Response, error) Get(path string, headers map[string]string) (*http.Response, error) Post(path, payload string, headers map[string]string) (*http.Response, error) + PostForm(path string, headers map[string]string, values map[string]string) (*http.Response, error) PostMultipart(path string, parts map[string]string, headers map[string]string) (*http.Response, error) Put(path, payload string, headers map[string]string) (*http.Response, error) Delete(path string, headers map[string]string) (*http.Response, error) diff --git a/pkg/http/curl/curl.go b/pkg/http/curl/curl.go index 71d4a0908..c017fbfed 100644 --- a/pkg/http/curl/curl.go +++ b/pkg/http/curl/curl.go @@ -60,6 +60,17 @@ func (c *Client) Post(path, payload string, headers map[string]string) (*http.Re return c.executeCurlCommand(path, headers, data, "-X POST") } +func (c *Client) PostForm(path string, headers map[string]string, values map[string]string) (*http.Response, error) { + data := make([]string, len(values)*2) + i := 0 + for k, v := range values { + data[i] = "-F" + data[i+1] = fmt.Sprintf("%s=\"%s\"", k, v) + i += 2 + } + return c.executeCurlCommand(path, headers, data...) +} + func (c *Client) PostMultipart(path string, parts map[string]string, headers map[string]string) (*http.Response, error) { var data string for k, v := range parts { diff --git a/pkg/infinispan/security/users.go b/pkg/infinispan/security/users.go index 903d533a2..c91c2d4f8 100644 --- a/pkg/infinispan/security/users.go +++ b/pkg/infinispan/security/users.go @@ -68,7 +68,7 @@ func CreateIdentitiesFor(usr string, pass string) ([]byte, error) { Credentials: []Credentials{{ Username: usr, Password: pass, - Roles: []string{"admin"}, + Roles: []string{"admin", "controlRole"}, }}, } data, err := yaml.Marshal(identities) diff --git a/pkg/reconcile/pipeline/infinispan/api.go b/pkg/reconcile/pipeline/infinispan/api.go index b1d54a139..7e44123be 100644 --- a/pkg/reconcile/pipeline/infinispan/api.go +++ b/pkg/reconcile/pipeline/infinispan/api.go @@ -7,6 +7,7 @@ import ( "github.com/go-logr/logr" ispnv1 "github.com/infinispan/infinispan-operator/api/v1" + cryostat "github.com/infinispan/infinispan-operator/pkg/apis/cryostat/v1beta1" ispnApi "github.com/infinispan/infinispan-operator/pkg/infinispan/client/api" config "github.com/infinispan/infinispan-operator/pkg/infinispan/configuration/server" "github.com/infinispan/infinispan-operator/pkg/infinispan/version" @@ -216,6 +217,7 @@ func SkipEventRec(config *ResourcesConfig) { // ConfigFiles is used to hold all configuration required by the Operand in provisioned resources type ConfigFiles struct { ConfigSpec config.Spec + Jmx bool ServerAdminConfig string ServerBaseConfig string ZeroConfig string @@ -289,4 +291,5 @@ var ( RouteGVK = routev1.SchemeGroupVersion.WithKind("Route") IngressGVK = ingressv1.SchemeGroupVersion.WithKind("Ingress") ServiceMonitorGVK = monitoringv1.SchemeGroupVersion.WithKind("ServiceMonitor") + CryostatGVK = cryostat.GroupVersion.WithKind("Cryostat") ) diff --git a/pkg/reconcile/pipeline/infinispan/handler/manage/cryostat.go b/pkg/reconcile/pipeline/infinispan/handler/manage/cryostat.go new file mode 100644 index 000000000..fc7218f85 --- /dev/null +++ b/pkg/reconcile/pipeline/infinispan/handler/manage/cryostat.go @@ -0,0 +1,163 @@ +package manage + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + v1 "github.com/infinispan/infinispan-operator/api/v1" + cryostatv1beta1 "github.com/infinispan/infinispan-operator/pkg/apis/cryostat/v1beta1" + httpClient "github.com/infinispan/infinispan-operator/pkg/http" + "github.com/infinispan/infinispan-operator/pkg/http/curl" + kube "github.com/infinispan/infinispan-operator/pkg/kubernetes" + pipeline "github.com/infinispan/infinispan-operator/pkg/reconcile/pipeline/infinispan" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + CryostatPort = 8181 + CryostatCredentialsApi = "api/v2.2/credentials" + requeueDelay = time.Second +) + +// CryostatCredentials initialises Cryostat credential store +// RequeueEventually is used throughout this function as failed Cryostat operations should not cause subsequent executions +// in the pipeline to fail +func CryostatCredentials(i *v1.Infinispan, ctx pipeline.Context) { + if !ctx.IsTypeSupported(pipeline.CryostatGVK) { + return + } + + log := ctx.Log() + cryostat := &cryostatv1beta1.Cryostat{} + if err := ctx.Resources().Load(i.GetCryostatName(), cryostat); err != nil { + log.Error(err, "unable to load Cryostat CR") + ctx.RequeueEventually(requeueDelay) + return + } + + // Ensure that the Cryostat deployment is ready before proceeding + availableCondition := metav1.Condition{Type: string(cryostatv1beta1.ConditionTypeMainDeploymentAvailable)} + for _, condition := range cryostat.Status.Conditions { + if condition.Type == string(cryostatv1beta1.ConditionTypeMainDeploymentAvailable) { + availableCondition = condition + break + } + } + if availableCondition.Status != metav1.ConditionTrue { + log.Info("Waiting for Cryostat deployment", "status", availableCondition.Status, "reason", availableCondition.Reason) + ctx.RequeueEventually(requeueDelay) + return + } + + cryostatLabels := map[string]string{ + "app": cryostat.Name, + "kind": "cryostat", + } + podList := &corev1.PodList{} + if err := ctx.Resources().List(cryostatLabels, podList); err != nil || len(podList.Items) == 0 { + log.Error(err, "unable to retrieve Cryostat pod") + ctx.RequeueEventually(requeueDelay) + return + } + + var cryostatPod string + for _, pod := range podList.Items { + if kube.IsPodReady(pod) { + cryostatPod = pod.Name + break + } + } + + if cryostatPod == "" { + log.Info("Waiting for Cryostat Pod to become Ready") + ctx.RequeueEventually(requeueDelay) + return + } + + client := curl.New(curl.Config{ + Container: cryostat.Name, + Namespace: cryostat.Namespace, + Podname: cryostatPod, + Protocol: "https", + Port: 8181, + }, ctx.Kubernetes()) + + token := base64.StdEncoding.EncodeToString([]byte(ctx.Kubernetes().RestConfig.BearerToken)) + headers := map[string]string{ + "Authorization": fmt.Sprintf("Bearer %s", token), + } + + // If the credential already exists, do nothing + if exists, err := credentialExists(headers, client, i); err != nil { + log.Error(err, "unable to determine if Cryostat credential already exists") + ctx.RequeueEventually(requeueDelay) + } else if !exists { + if err := createCredential(headers, client, i, ctx); err != nil { + log.Error(err, "unable to add Cryostat credentials") + ctx.RequeueEventually(requeueDelay) + } + } +} + +func credentialExists(headers map[string]string, client httpClient.HttpClient, i *v1.Infinispan) (bool, error) { + rsp, err := client.Get(CryostatCredentialsApi, headers) + defer func() { + err = httpClient.CloseBody(rsp, err) + }() + if err := httpClient.ValidateResponse(rsp, err, "checking Cryostat credential", http.StatusOK); err != nil { + return false, err + } + + type payload struct { + Data struct { + Result []struct { + MatchExpression string `json:"matchExpression"` + } `json:"result"` + } `json:"data"` + } + + rspBody, err := io.ReadAll(rsp.Body) + if err != nil { + return false, fmt.Errorf("unable to read response body: %w", err) + } + + parsedRsp := &payload{} + if err := json.Unmarshal(rspBody, parsedRsp); err != nil { + return false, fmt.Errorf("unable to parse JSON: %w", err) + } + + matchExpression := MatchExpression(i) + for _, cred := range parsedRsp.Data.Result { + if cred.MatchExpression == matchExpression { + return true, nil + } + } + return false, nil +} + +func createCredential(headers map[string]string, client httpClient.HttpClient, i *v1.Infinispan, ctx pipeline.Context) error { + admin := ctx.ConfigFiles().AdminIdentities + formData := map[string]string{ + "matchExpression": MatchExpression(i), + "username": admin.Username, + "password": admin.Password, + } + + rsp, err := client.PostForm(CryostatCredentialsApi, headers, formData) + defer func() { + err = httpClient.CloseBody(rsp, err) + }() + if err := httpClient.ValidateResponse(rsp, err, "adding Cryostat credentials", http.StatusCreated); err != nil { + return err + } + return nil +} + +func MatchExpression(i *v1.Infinispan) string { + return fmt.Sprintf("target.labels['infinispan_cr'] == '%s'", i.Name) +} diff --git a/pkg/reconcile/pipeline/infinispan/handler/manage/statefulset_updates.go b/pkg/reconcile/pipeline/infinispan/handler/manage/statefulset_updates.go index 1e94d3aa3..92d55e9c7 100644 --- a/pkg/reconcile/pipeline/infinispan/handler/manage/statefulset_updates.go +++ b/pkg/reconcile/pipeline/infinispan/handler/manage/statefulset_updates.go @@ -102,7 +102,7 @@ func StatefulSetRollingUpgrade(i *ispnv1.Infinispan, ctx pipeline.Context) { updateNeeded = updateStatefulSetEnv(container, statefulSet, "CONFIG_HASH", hash.HashString(configFiles.ServerBaseConfig, configFiles.ServerAdminConfig)) || updateNeeded updateNeeded = updateStatefulSetEnv(container, statefulSet, "ADMIN_IDENTITIES_HASH", hash.HashByte(configFiles.AdminIdentities.IdentitiesFile)) || updateNeeded - if updateCmdArgs, err := updateStartupArgs(container, configFiles.UserConfig); err != nil { + if updateCmdArgs, err := updateStartupArgs(container, configFiles); err != nil { ctx.Requeue(err) return } else { @@ -198,8 +198,8 @@ func updateStatefulSetEnv(ispnContainer *corev1.Container, statefulSet *appsv1.S } return false } -func updateStartupArgs(ispnContainer *corev1.Container, userConfig pipeline.UserConfig) (bool, error) { - newArgs := provision.BuildServerContainerArgs(userConfig) +func updateStartupArgs(ispnContainer *corev1.Container, config *pipeline.ConfigFiles) (bool, error) { + newArgs := provision.BuildServerContainerArgs(config) if len(newArgs) == len(ispnContainer.Args) { var changed bool for i := range newArgs { diff --git a/pkg/reconcile/pipeline/infinispan/handler/provision/cryostat.go b/pkg/reconcile/pipeline/infinispan/handler/provision/cryostat.go new file mode 100644 index 000000000..0e4e6a32c --- /dev/null +++ b/pkg/reconcile/pipeline/infinispan/handler/provision/cryostat.go @@ -0,0 +1,39 @@ +package provision + +import ( + "fmt" + + v1 "github.com/infinispan/infinispan-operator/api/v1" + cryostatv1beta1 "github.com/infinispan/infinispan-operator/pkg/apis/cryostat/v1beta1" + pipeline "github.com/infinispan/infinispan-operator/pkg/reconcile/pipeline/infinispan" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +func Cryostat(i *v1.Infinispan, ctx pipeline.Context) { + if !ctx.IsTypeSupported(pipeline.CryostatGVK) { + return + } + + cryostat := &cryostatv1beta1.Cryostat{ + TypeMeta: metav1.TypeMeta{ + APIVersion: cryostatv1beta1.GroupVersion.String(), + Kind: "Cryostat", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: i.GetCryostatName(), + Namespace: i.Namespace, + }, + } + + mutateFn := func() error { + cryostat.Spec.Minimal = false + cryostat.Spec.EnableCertManager = pointer.Bool(true) + return controllerutil.SetOwnerReference(i, cryostat, ctx.Kubernetes().Client.Scheme()) + } + + if _, err := ctx.Resources().CreateOrUpdate(cryostat, false, mutateFn); err != nil { + ctx.Requeue(fmt.Errorf("unable to createOrUpdate Cryostat: %w", err)) + } +} diff --git a/pkg/reconcile/pipeline/infinispan/handler/provision/pods.go b/pkg/reconcile/pipeline/infinispan/handler/provision/pods.go index 3ae56b5b3..08b94f122 100644 --- a/pkg/reconcile/pipeline/infinispan/handler/provision/pods.go +++ b/pkg/reconcile/pipeline/infinispan/handler/provision/pods.go @@ -19,6 +19,10 @@ func PodPortsWithXsite(i *ispnv1.Infinispan) []corev1.ContainerPort { {ContainerPort: consts.InfinispanUserPort, Name: consts.InfinispanUserPortName, Protocol: corev1.ProtocolTCP}, } + if i.IsCryostatEnabled() { + ports = append(ports, corev1.ContainerPort{ContainerPort: consts.InfinispanJmxPort, Name: consts.InfinispanJmxPortName, Protocol: corev1.ProtocolTCP}) + } + if i.HasSites() { ports = append(ports, corev1.ContainerPort{ContainerPort: consts.CrossSitePort, Name: consts.CrossSitePortName, Protocol: corev1.ProtocolTCP}) } diff --git a/pkg/reconcile/pipeline/infinispan/handler/provision/services.go b/pkg/reconcile/pipeline/infinispan/handler/provision/services.go index f4635cf57..984c57ef0 100644 --- a/pkg/reconcile/pipeline/infinispan/handler/provision/services.go +++ b/pkg/reconcile/pipeline/infinispan/handler/provision/services.go @@ -82,14 +82,24 @@ func AdminService(i *ispnv1.Infinispan, ctx pipeline.Context) { svc.Spec.Selector = i.ServiceSelectorLabels() // We must utilise the existing ServicePort values if updating the service, to prevent the created ports being overwritten if svc.CreationTimestamp.IsZero() { - svc.Spec.Ports = []corev1.ServicePort{{}} + if i.IsCryostatEnabled() { + svc.Spec.Ports = []corev1.ServicePort{{}, {}} + } else { + svc.Spec.Ports = []corev1.ServicePort{{}} + } // If an upgrade is in progress, we wait for the GracefulShutdown to destroy the old admin service before // defining a new one with ClusterIpNone svc.Spec.ClusterIP = corev1.ClusterIPNone } - servicePort := &svc.Spec.Ports[0] - servicePort.Name = consts.InfinispanAdminPortName - servicePort.Port = consts.InfinispanAdminPort + singlePort := &svc.Spec.Ports[0] + singlePort.Name = consts.InfinispanAdminPortName + singlePort.Port = consts.InfinispanAdminPort + + if i.IsCryostatEnabled() { + cryostatPort := &svc.Spec.Ports[1] + cryostatPort.Name = consts.InfinispanJmxPortName + cryostatPort.Port = consts.InfinispanJmxPort + } return nil } _, _ = ctx.Resources().CreateOrUpdate(svc, true, mutateFn, pipeline.RetryOnErr) diff --git a/pkg/reconcile/pipeline/infinispan/handler/provision/statefulsets.go b/pkg/reconcile/pipeline/infinispan/handler/provision/statefulsets.go index 9d10e8ed0..e7edde190 100644 --- a/pkg/reconcile/pipeline/infinispan/handler/provision/statefulsets.go +++ b/pkg/reconcile/pipeline/infinispan/handler/provision/statefulsets.go @@ -104,7 +104,7 @@ func ClusterStatefulSetSpec(statefulSetName string, i *ispnv1.Infinispan, ctx pi Affinity: i.Spec.Affinity, Containers: []corev1.Container{{ Image: i.ImageName(), - Args: BuildServerContainerArgs(ctx.ConfigFiles().UserConfig), + Args: BuildServerContainerArgs(ctx.ConfigFiles()), Name: InfinispanContainer, Env: PodEnv(i, &[]corev1.EnvVar{ {Name: "CONFIG_HASH", Value: hash.HashString(configFiles.ServerBaseConfig, configFiles.ServerAdminConfig)}, @@ -258,14 +258,18 @@ func addUserConfigVolumes(ctx pipeline.Context, i *ispnv1.Infinispan, statefulse }) } -func BuildServerContainerArgs(userConfig pipeline.UserConfig) []string { +func BuildServerContainerArgs(config *pipeline.ConfigFiles) []string { var args strings.Builder // Preallocate a buffer to speed up string building (saves code from growing the memory dynamically) args.Grow(110) + if config.Jmx { + args.WriteString(" --jmx ") + } // Check if the user defined a custom log4j config args.WriteString(" -l ") + userConfig := config.UserConfig if userConfig.Log4j != "" { args.WriteString("user/log4j.xml") } else { diff --git a/pkg/reconcile/pipeline/infinispan/pipeline/pipeline.go b/pkg/reconcile/pipeline/infinispan/pipeline/pipeline.go index b4f78e5b5..8adfad601 100644 --- a/pkg/reconcile/pipeline/infinispan/pipeline/pipeline.go +++ b/pkg/reconcile/pipeline/infinispan/pipeline/pipeline.go @@ -192,11 +192,13 @@ func (b *builder) Build() pipeline.Pipeline { provision.ClusterStatefulSet, provision.ServiceMonitor, ) + handlers.AddFeatureSpecific(i.IsCryostatEnabled(), provision.Cryostat) handlers.AddFeatureSpecific(i.IsExposed(), provision.ExternalService) } // Manage the created Cluster handlers.Add(manage.PodStatus) + handlers.AddFeatureSpecific(i.IsCryostatEnabled(), manage.CryostatCredentials) handlers.AddFeatureSpecific(i.HotRodRollingUpgrades(), manage.HotRodRollingUpgrade) handlers.AddFeatureSpecific(i.GracefulShutdownUpgrades(), manage.GracefulShutdownUpgrade) handlers.Add( diff --git a/pkg/templates/rice-box.go b/pkg/templates/rice-box.go index c4ee07633..d5c5549b9 100644 --- a/pkg/templates/rice-box.go +++ b/pkg/templates/rice-box.go @@ -20,7 +20,7 @@ func init() { Filename: "infinispan-admin-14.xml", FileModTime: time.Unix(1620137619, 0), - Content: string("\n\n\n \n \n \n {{ if .JGroups.FastMerge }}\n \n {{ end }}\n \n {{ if .XSite }} {{ if .XSite.Sites }}\n \n \n \n \n \n {{ if .JGroups.FastMerge }}\n \n {{ end }}\n \n \n \n {{ range $it := .XSite.Sites }}\n \n {{ end }}\n \n {{ end }} {{ end }}\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n"), + Content: string("\n\n\n \n \n \n {{ if .JGroups.FastMerge }}\n \n {{ end }}\n \n {{ if .XSite }} {{ if .XSite.Sites }}\n \n \n \n \n \n {{ if .JGroups.FastMerge }}\n \n {{ end }}\n \n \n \n {{ range $it := .XSite.Sites }}\n \n {{ end }}\n \n {{ end }} {{ end }}\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n"), } file6 := &embedded.EmbeddedFile{ Filename: "infinispan-base-13.xml", diff --git a/pkg/templates/templates/infinispan-admin-14.xml b/pkg/templates/templates/infinispan-admin-14.xml index d27bce7e7..5071e08e3 100644 --- a/pkg/templates/templates/infinispan-admin-14.xml +++ b/pkg/templates/templates/infinispan-admin-14.xml @@ -66,7 +66,7 @@ - + diff --git a/scripts/ci/kind-with-olm.sh b/scripts/ci/kind-with-olm.sh index a298f58e9..d82817b18 100755 --- a/scripts/ci/kind-with-olm.sh +++ b/scripts/ci/kind-with-olm.sh @@ -1,6 +1,20 @@ #!/usr/bin/env bash set -o errexit +# Wait for k8s resource to exist. See: https://github.com/kubernetes/kubernetes/issues/83242 +waitFor() { + xtrace=$(set +o|grep xtrace); set +x + local ns=${1?namespace is required}; shift + local type=${1?type is required}; shift + + echo "Waiting for $type $*" + until oc -n "$ns" get "$type" "$@" -o=jsonpath='{.items[0].metadata.name}' >/dev/null 2>&1; do + echo "Waiting for $type $*" + sleep 1 + done + eval "$xtrace" +} + SCRIPT_DIR=$(dirname "$0") OLM_VERSION="v0.21.2" @@ -13,3 +27,20 @@ operator-sdk olm install --version ${OLM_VERSION} kubectl wait --for=condition=available --timeout=60s deployment/catalog-operator -n olm kubectl wait --for=condition=available --timeout=60s deployment/olm-operator -n olm kubectl wait --for=condition=available --timeout=60s deployment/packageserver -n olm + +# Install Cryostat Operator +cat <