You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ha...@apache.org on 2020/02/27 04:48:47 UTC
[skywalking-swck] 04/06: Add OAP Server CRDs
This is an automated email from the ASF dual-hosted git repository.
hanahmily pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-swck.git
commit 8d7d8f7a6c83a78a7a28722da787c6531be12604
Author: Gao Hongtao <ha...@gmail.com>
AuthorDate: Wed Feb 26 11:16:09 2020 +0800
Add OAP Server CRDs
Signed-off-by: Gao Hongtao <ha...@gmail.com>
---
PROJECT | 4 +
api/v1alpha1/groupversion_info.go | 37 ++
api/v1alpha1/oapserver_types.go | 99 +++
api/v1alpha1/zz_generated.deepcopy.go | 151 +++++
.../operator.skywalking.apache.org_oapservers.yaml | 721 +++++++++++++++++++++
config/crd/kustomization.yaml | 21 +
config/crd/kustomizeconfig.yaml | 17 +
config/crd/patches/cainjection_in_oapservers.yaml | 8 +
config/crd/patches/webhook_in_oapservers.yaml | 17 +
config/rbac/oapserver_editor_role.yaml | 24 +
config/rbac/oapserver_viewer_role.yaml | 20 +
config/rbac/role.yaml | 28 +
config/webhook/manifests.yaml | 0
controllers/oapserver_controller.go | 54 ++
controllers/suite_test.go | 81 +++
go.mod | 4 +
main.go | 12 +
17 files changed, 1298 insertions(+)
diff --git a/PROJECT b/PROJECT
index 0b30de2..e04083d 100644
--- a/PROJECT
+++ b/PROJECT
@@ -1,3 +1,7 @@
domain: skywalking.apache.org
repo: github.com/skywalking-swck
+resources:
+- group: operator
+ kind: OAPServer
+ version: v1alpha1
version: "2"
diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go
new file mode 100644
index 0000000..cba2eb5
--- /dev/null
+++ b/api/v1alpha1/groupversion_info.go
@@ -0,0 +1,37 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Package v1alpha1 contains API Schema definitions for the operator v1alpha1 API group
+// +kubebuilder:object:generate=true
+// +groupName=operator.skywalking.apache.org
+package v1alpha1
+
+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.skywalking.apache.org", Version: "v1alpha1"}
+
+ // 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/api/v1alpha1/oapserver_types.go b/api/v1alpha1/oapserver_types.go
new file mode 100644
index 0000000..6773111
--- /dev/null
+++ b/api/v1alpha1/oapserver_types.go
@@ -0,0 +1,99 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package v1alpha1
+
+import (
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// OAPServerSpec defines the desired state of OAPServer
+type OAPServerSpec struct {
+ // Version of OAP.
+ Version string `json:"version"`
+ // Image is the OAP Server Docker image to deploy.
+ Image string `json:"image,omitempty"`
+ // Count is the number of OAP servers
+ Instances int `json:"instances,imitempty"`
+ // Config holds the OAP server configuration.
+ Config map[string]string `json:"config,omitempty"`
+
+ // NodeSelector is a selector which must be true for the pod to fit on a node.
+ // Selector which must match a node's labels for the pod to be scheduled on that node.
+ // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
+ // +kubebuilder:validation:Optional
+ NodeSelector map[string]string `json:"nodeSelector,omitempty"`
+ // If specified, affinity will define the pod's scheduling constraints
+ // +kubebuilder:validation:Optional
+ Affinity *corev1.Affinity `json:"affinity,omitempty"`
+ // Tolerations allows specifying a list of tolerations for controlling which
+ // set of Nodes a Pod can be scheduled on
+ // +kubebuilder:validation:Optional
+ Tolerations *[]corev1.Toleration `json:"tolerations,omitempty"`
+ // Resources holds ResourceRequirements for the OAP server containers
+ // +kubebuilder:validation:Optional
+ Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
+}
+
+// OAPServerPhase is the phase OAP server is in from the controller point of view.
+type OAPServerPhase string
+
+const (
+ // OAPServerReadyPhase is operating at the desired spec.
+ OAPServerReadyPhase OAPServerPhase = "Ready"
+ // OAPServerChangingPhase controller is working towards a desired state, cluster can be unavailable.
+ OAPServerChangingPhase OAPServerPhase = "Changing"
+ // OAPServerResourceInvalid is marking a resource as invalid, should never happen if admission control is installed correctly.
+ OAPServerResourceInvalid OAPServerPhase = "Invalid"
+)
+
+// OAPServerStatus defines the observed state of OAPServer
+type OAPServerStatus struct {
+ // The phase OAP servers is in.
+ Phase OAPServerPhase `json:"phase,omitempty"`
+ // A human readable message indicating details about why the OAP servers is in this phase.
+ // +kubebuilder:validation:Optional
+ Message string `json:"message,omitempty"`
+ // A brief CamelCase message indicating details about why the OAP servers is in this state.
+ // +kubebuilder:validation:Optional
+ Reason string `json:"reason,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// OAPServer is the Schema for the oapservers API
+type OAPServer struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec OAPServerSpec `json:"spec,omitempty"`
+ Status OAPServerStatus `json:"status,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// OAPServerList contains a list of OAPServer
+type OAPServerList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []OAPServer `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&OAPServer{}, &OAPServerList{})
+}
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 0000000..80f4197
--- /dev/null
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,151 @@
+// +build !ignore_autogenerated
+
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ "k8s.io/api/core/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 *OAPServer) DeepCopyInto(out *OAPServer) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+ in.Spec.DeepCopyInto(&out.Spec)
+ out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAPServer.
+func (in *OAPServer) DeepCopy() *OAPServer {
+ if in == nil {
+ return nil
+ }
+ out := new(OAPServer)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *OAPServer) 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 *OAPServerList) DeepCopyInto(out *OAPServerList) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ListMeta.DeepCopyInto(&out.ListMeta)
+ if in.Items != nil {
+ in, out := &in.Items, &out.Items
+ *out = make([]OAPServer, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAPServerList.
+func (in *OAPServerList) DeepCopy() *OAPServerList {
+ if in == nil {
+ return nil
+ }
+ out := new(OAPServerList)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *OAPServerList) 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 *OAPServerSpec) DeepCopyInto(out *OAPServerSpec) {
+ *out = *in
+ if in.Config != nil {
+ in, out := &in.Config, &out.Config
+ *out = make(map[string]string, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
+ 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(v1.Affinity)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Tolerations != nil {
+ in, out := &in.Tolerations, &out.Tolerations
+ *out = new([]v1.Toleration)
+ if **in != nil {
+ in, out := *in, *out
+ *out = make([]v1.Toleration, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ }
+ if in.Resources != nil {
+ in, out := &in.Resources, &out.Resources
+ *out = new(v1.ResourceRequirements)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAPServerSpec.
+func (in *OAPServerSpec) DeepCopy() *OAPServerSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(OAPServerSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OAPServerStatus) DeepCopyInto(out *OAPServerStatus) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OAPServerStatus.
+func (in *OAPServerStatus) DeepCopy() *OAPServerStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(OAPServerStatus)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/config/crd/bases/operator.skywalking.apache.org_oapservers.yaml b/config/crd/bases/operator.skywalking.apache.org_oapservers.yaml
new file mode 100644
index 0000000..42525f7
--- /dev/null
+++ b/config/crd/bases/operator.skywalking.apache.org_oapservers.yaml
@@ -0,0 +1,721 @@
+
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ controller-gen.kubebuilder.io/version: v0.2.4
+ creationTimestamp: null
+ name: oapservers.operator.skywalking.apache.org
+spec:
+ group: operator.skywalking.apache.org
+ names:
+ kind: OAPServer
+ listKind: OAPServerList
+ plural: oapservers
+ singular: oapserver
+ scope: Namespaced
+ validation:
+ openAPIV3Schema:
+ description: OAPServer is the Schema for the oapservers API
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation
+ of an object. Servers should convert recognized schemas to the latest
+ internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this
+ object represents. Servers may infer this from the endpoint the client
+ submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: OAPServerSpec defines the desired state of OAPServer
+ properties:
+ affinity:
+ description: If specified, affinity will define the pod's scheduling
+ constraints
+ properties:
+ nodeAffinity:
+ description: Describes node affinity scheduling rules for the pod.
+ 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: Describes pod affinity scheduling rules (e.g. co-locate
+ this pod in the same node, zone, etc. as some other pod(s)).
+ 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 <topologyKey>
+ 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: Describes pod anti-affinity scheduling rules (e.g.
+ avoid putting this pod in the same node, zone, etc. as some other
+ pod(s)).
+ 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 <topologyKey>
+ 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
+ config:
+ additionalProperties:
+ type: string
+ description: Config holds the OAP server configuration.
+ type: object
+ image:
+ description: Image is the OAP Server Docker image to deploy.
+ type: string
+ instances:
+ description: Count is the number of OAP servers
+ type: integer
+ nodeSelector:
+ additionalProperties:
+ type: string
+ description: 'NodeSelector is a selector which must be true for the
+ pod to fit on a node. Selector which must match a node''s labels for
+ the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/'
+ type: object
+ resources:
+ description: Resources holds ResourceRequirements for the OAP server
+ containers
+ properties:
+ limits:
+ additionalProperties:
+ type: string
+ 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:
+ type: string
+ 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
+ tolerations:
+ description: Tolerations allows specifying a list of tolerations for
+ controlling which set of Nodes a Pod can be scheduled on
+ items:
+ description: The pod this Toleration is attached to tolerates any
+ taint that matches the triple <key,value,effect> using the matching
+ operator <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
+ version:
+ description: Version of OAP.
+ type: string
+ required:
+ - instances
+ - version
+ type: object
+ status:
+ description: OAPServerStatus defines the observed state of OAPServer
+ properties:
+ message:
+ description: A human readable message indicating details about why the
+ OAP servers is in this phase.
+ type: string
+ phase:
+ description: The phase OAP servers is in.
+ type: string
+ reason:
+ description: A brief CamelCase message indicating details about why
+ the OAP servers is in this state.
+ type: string
+ type: object
+ type: object
+ version: v1alpha1
+ versions:
+ - name: v1alpha1
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
new file mode 100644
index 0000000..b391b8e
--- /dev/null
+++ b/config/crd/kustomization.yaml
@@ -0,0 +1,21 @@
+# This kustomization.yaml is not intended to be run by itself,
+# since it depends on service name and namespace that are out of this kustomize package.
+# It should be run by config/default
+resources:
+- bases/operator.skywalking.apache.org_oapservers.yaml
+# +kubebuilder:scaffold:crdkustomizeresource
+
+patchesStrategicMerge:
+# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
+# patches here are for enabling the conversion webhook for each CRD
+#- patches/webhook_in_oapservers.yaml
+# +kubebuilder:scaffold:crdkustomizewebhookpatch
+
+# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
+# patches here are for enabling the CA injection for each CRD
+#- patches/cainjection_in_oapservers.yaml
+# +kubebuilder:scaffold:crdkustomizecainjectionpatch
+
+# the following config is for teaching kustomize how to do kustomization for CRDs.
+configurations:
+- kustomizeconfig.yaml
diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml
new file mode 100644
index 0000000..6f83d9a
--- /dev/null
+++ b/config/crd/kustomizeconfig.yaml
@@ -0,0 +1,17 @@
+# This file is for teaching kustomize how to substitute name and namespace reference in CRD
+nameReference:
+- kind: Service
+ version: v1
+ fieldSpecs:
+ - kind: CustomResourceDefinition
+ group: apiextensions.k8s.io
+ path: spec/conversion/webhookClientConfig/service/name
+
+namespace:
+- kind: CustomResourceDefinition
+ group: apiextensions.k8s.io
+ path: spec/conversion/webhookClientConfig/service/namespace
+ create: false
+
+varReference:
+- path: metadata/annotations
diff --git a/config/crd/patches/cainjection_in_oapservers.yaml b/config/crd/patches/cainjection_in_oapservers.yaml
new file mode 100644
index 0000000..17e24cf
--- /dev/null
+++ b/config/crd/patches/cainjection_in_oapservers.yaml
@@ -0,0 +1,8 @@
+# The following patch adds a directive for certmanager to inject CA into the CRD
+# CRD conversion requires k8s 1.13 or later.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ annotations:
+ cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
+ name: oapservers.operator.skywalking.apache.org
diff --git a/config/crd/patches/webhook_in_oapservers.yaml b/config/crd/patches/webhook_in_oapservers.yaml
new file mode 100644
index 0000000..b1846c1
--- /dev/null
+++ b/config/crd/patches/webhook_in_oapservers.yaml
@@ -0,0 +1,17 @@
+# The following patch enables conversion webhook for CRD
+# CRD conversion requires k8s 1.13 or later.
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+ name: oapservers.operator.skywalking.apache.org
+spec:
+ conversion:
+ strategy: Webhook
+ webhookClientConfig:
+ # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
+ # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
+ caBundle: Cg==
+ service:
+ namespace: system
+ name: webhook-service
+ path: /convert
diff --git a/config/rbac/oapserver_editor_role.yaml b/config/rbac/oapserver_editor_role.yaml
new file mode 100644
index 0000000..5c46c84
--- /dev/null
+++ b/config/rbac/oapserver_editor_role.yaml
@@ -0,0 +1,24 @@
+# permissions for end users to edit oapservers.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: oapserver-editor-role
+rules:
+- apiGroups:
+ - operator.skywalking.apache.org
+ resources:
+ - oapservers
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - operator.skywalking.apache.org
+ resources:
+ - oapservers/status
+ verbs:
+ - get
diff --git a/config/rbac/oapserver_viewer_role.yaml b/config/rbac/oapserver_viewer_role.yaml
new file mode 100644
index 0000000..97cdbab
--- /dev/null
+++ b/config/rbac/oapserver_viewer_role.yaml
@@ -0,0 +1,20 @@
+# permissions for end users to view oapservers.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: oapserver-viewer-role
+rules:
+- apiGroups:
+ - operator.skywalking.apache.org
+ resources:
+ - oapservers
+ verbs:
+ - get
+ - list
+ - watch
+- apiGroups:
+ - operator.skywalking.apache.org
+ resources:
+ - oapservers/status
+ verbs:
+ - get
diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml
new file mode 100644
index 0000000..8424a5f
--- /dev/null
+++ b/config/rbac/role.yaml
@@ -0,0 +1,28 @@
+
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ creationTimestamp: null
+ name: manager-role
+rules:
+- apiGroups:
+ - operator.skywalking.apache.org
+ resources:
+ - oapservers
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
+- apiGroups:
+ - operator.skywalking.apache.org
+ resources:
+ - oapservers/status
+ verbs:
+ - get
+ - patch
+ - update
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
new file mode 100644
index 0000000..e69de29
diff --git a/controllers/oapserver_controller.go b/controllers/oapserver_controller.go
new file mode 100644
index 0000000..fd107bc
--- /dev/null
+++ b/controllers/oapserver_controller.go
@@ -0,0 +1,54 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package controllers
+
+import (
+ "context"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/runtime"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+
+ operatorv1alpha1 "github.com/skywalking-swck/api/v1alpha1"
+)
+
+// OAPServerReconciler reconciles a OAPServer object
+type OAPServerReconciler struct {
+ client.Client
+ Log logr.Logger
+ Scheme *runtime.Scheme
+}
+
+// +kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=oapservers,verbs=get;list;watch;create;update;patch;delete
+// +kubebuilder:rbac:groups=operator.skywalking.apache.org,resources=oapservers/status,verbs=get;update;patch
+
+func (r *OAPServerReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
+ _ = context.Background()
+ _ = r.Log.WithValues("oapserver", req.NamespacedName)
+
+ // your logic here
+
+ return ctrl.Result{}, nil
+}
+
+func (r *OAPServerReconciler) SetupWithManager(mgr ctrl.Manager) error {
+ return ctrl.NewControllerManagedBy(mgr).
+ For(&operatorv1alpha1.OAPServer{}).
+ Complete(r)
+}
diff --git a/controllers/suite_test.go b/controllers/suite_test.go
new file mode 100644
index 0000000..da4c6d1
--- /dev/null
+++ b/controllers/suite_test.go
@@ -0,0 +1,81 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package controllers
+
+import (
+ "path/filepath"
+ "testing"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/envtest"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+ operatorv1alpha1 "github.com/skywalking-swck/api/v1alpha1"
+ // +kubebuilder:scaffold:imports
+)
+
+// These tests use Ginkgo (BDD-style Go testing framework). Refer to
+// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
+
+var cfg *rest.Config
+var k8sClient client.Client
+var testEnv *envtest.Environment
+
+func TestAPIs(t *testing.T) {
+ RegisterFailHandler(Fail)
+
+ RunSpecsWithDefaultAndCustomReporters(t,
+ "Controller Suite",
+ []Reporter{envtest.NewlineReporter{}})
+}
+
+var _ = BeforeSuite(func(done Done) {
+ logf.SetLogger(zap.LoggerTo(GinkgoWriter, true))
+
+ By("bootstrapping test environment")
+ testEnv = &envtest.Environment{
+ CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
+ }
+
+ var err error
+ cfg, err = testEnv.Start()
+ Expect(err).ToNot(HaveOccurred())
+ Expect(cfg).ToNot(BeNil())
+
+ err = operatorv1alpha1.AddToScheme(scheme.Scheme)
+ Expect(err).NotTo(HaveOccurred())
+
+ // +kubebuilder:scaffold:scheme
+
+ k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
+ Expect(err).ToNot(HaveOccurred())
+ Expect(k8sClient).ToNot(BeNil())
+
+ close(done)
+}, 60)
+
+var _ = AfterSuite(func() {
+ By("tearing down the test environment")
+ err := testEnv.Stop()
+ Expect(err).ToNot(HaveOccurred())
+})
diff --git a/go.mod b/go.mod
index f37ced2..6082d91 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,10 @@ module github.com/skywalking-swck
go 1.13
require (
+ github.com/go-logr/logr v0.1.0
+ github.com/onsi/ginkgo v1.8.0
+ github.com/onsi/gomega v1.5.0
+ k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90
sigs.k8s.io/controller-runtime v0.4.0
diff --git a/main.go b/main.go
index f4851c7..0cfcf25 100644
--- a/main.go
+++ b/main.go
@@ -26,6 +26,9 @@ import (
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+ operatorv1alpha1 "github.com/skywalking-swck/api/v1alpha1"
+ "github.com/skywalking-swck/controllers"
// +kubebuilder:scaffold:imports
)
@@ -37,6 +40,7 @@ var (
func init() {
_ = clientgoscheme.AddToScheme(scheme)
+ _ = operatorv1alpha1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
}
@@ -64,6 +68,14 @@ func main() {
os.Exit(1)
}
+ if err = (&controllers.OAPServerReconciler{
+ Client: mgr.GetClient(),
+ Log: ctrl.Log.WithName("controllers").WithName("OAPServer"),
+ Scheme: mgr.GetScheme(),
+ }).SetupWithManager(mgr); err != nil {
+ setupLog.Error(err, "unable to create controller", "controller", "OAPServer")
+ os.Exit(1)
+ }
// +kubebuilder:scaffold:builder
setupLog.Info("starting manager")