This is an automated email from the ASF dual-hosted git repository. kezhenxu94 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/dolphinscheduler-operator.git
commit c5518951aee8b334d2058dbf8e332ac18ed0b0ee Author: nobolity <[email protected]> AuthorDate: Sun May 29 21:49:46 2022 +0800 feat(operator): add api --- PROJECT | 9 + api/v1alpha1/ds_public.go | 6 + api/v1alpha1/zz_generated.deepcopy.go | 89 ++ .../ds.apache.dolphinscheduler.dev_dsalerts.yaml | 1601 ++++++++++++++++++++ config/crd/kustomization.yaml | 3 + config/crd/patches/cainjection_in_dsalerts.yaml | 7 + config/crd/patches/webhook_in_dsalerts.yaml | 16 + config/ds/alert/ds-alert-deployment.yaml | 30 - config/ds/alert/ds-alert-service.yaml | 17 - config/rbac/dsalert_editor_role.yaml | 24 + config/rbac/dsalert_viewer_role.yaml | 20 + config/rbac/role.yaml | 26 + config/samples/ds_v1alpha1_dsalert.yaml | 16 + controllers/alert_reconcile.go | 22 +- .../{alert_reconcile.go => api_reconcile.go} | 36 +- controllers/dsalert_controller.go | 221 +++ controllers/dsmaster_controller.go | 11 +- controllers/dsworker_controller.go | 2 +- controllers/suite_test.go | 2 +- main.go | 7 + 20 files changed, 2080 insertions(+), 85 deletions(-) diff --git a/PROJECT b/PROJECT index 55173fc..14f9538 100644 --- a/PROJECT +++ b/PROJECT @@ -31,4 +31,13 @@ resources: kind: DSAlert path: dolphinscheduler-operator/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: apache.dolphinscheduler.dev + group: ds + kind: DSApi + path: dolphinscheduler-operator/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/api/v1alpha1/ds_public.go b/api/v1alpha1/ds_public.go index bf82016..d468fca 100644 --- a/api/v1alpha1/ds_public.go +++ b/api/v1alpha1/ds_public.go @@ -30,12 +30,18 @@ const ( EnvZookeeper = "REGISTRY_ZOOKEEPER_CONNECT_STRING" DsServiceLabel = "service-name" DsServiceLabelValue = "ds-service" + DsAlert = "ds-alert" DsAlertServiceValue = "ds-alert-service" DsAlertDeploymentValue = "ds-alert-deployment" + DsApi = "ds-api" + DsApiServiceValue = "ds-api-service" + DsApiDeploymentValue = "ds-api-deployment" DataSourceDriveName = "SPRING_DATASOURCE_DRIVER_CLASS_NAME" DataSourceUrl = "SPRING_DATASOURCE_URL" DataSourceUserName = "SPRING_DATASOURCE_USERNAME" DataSourcePassWord = "SPRING_DATASOURCE_PASSWORD" + DsApiPort = 12345 + DsAlertPort = 50052 ) // DsCondition represents one current condition of a ds cluster. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 4592b8f..f69ee99 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -146,6 +146,95 @@ func (in *DSAlertStatus) DeepCopy() *DSAlertStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DSApi) DeepCopyInto(out *DSApi) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DSApi. +func (in *DSApi) DeepCopy() *DSApi { + if in == nil { + return nil + } + out := new(DSApi) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DSApi) 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 *DSApiList) DeepCopyInto(out *DSApiList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]DSApi, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DSApiList. +func (in *DSApiList) DeepCopy() *DSApiList { + if in == nil { + return nil + } + out := new(DSApiList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DSApiList) 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 *DSApiSpec) DeepCopyInto(out *DSApiSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DSApiSpec. +func (in *DSApiSpec) DeepCopy() *DSApiSpec { + if in == nil { + return nil + } + out := new(DSApiSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DSApiStatus) DeepCopyInto(out *DSApiStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DSApiStatus. +func (in *DSApiStatus) DeepCopy() *DSApiStatus { + if in == nil { + return nil + } + out := new(DSApiStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DSMaster) DeepCopyInto(out *DSMaster) { *out = *in diff --git a/config/crd/bases/ds.apache.dolphinscheduler.dev_dsalerts.yaml b/config/crd/bases/ds.apache.dolphinscheduler.dev_dsalerts.yaml new file mode 100644 index 0000000..b49a713 --- /dev/null +++ b/config/crd/bases/ds.apache.dolphinscheduler.dev_dsalerts.yaml @@ -0,0 +1,1601 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: dsalerts.ds.apache.dolphinscheduler.dev +spec: + group: ds.apache.dolphinscheduler.dev + names: + kind: DSAlert + listKind: DSAlertList + plural: dsalerts + singular: dsalert + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: DSAlert is the Schema for the dsalerts 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: DSAlertSpec defines the desired state of DSAlert + properties: + datasource: + properties: + drive_name: + type: string + password: + type: string + url: + type: string + username: + type: string + required: + - drive_name + - password + - url + - username + type: object + log_pvc_name: + description: LogPvcName defines the log capacity of application ,the + position is /opt/dolphinscheduler/logs eg 20Gi + type: string + paused: + default: false + description: Paused is to pause the control of the operator for the + ds-master . + type: boolean + pod: + description: Pod defines the policy to create pod for the dm-master + pod. Updating Pod does not take effect on any existing dm-master + pods. + properties: + affinity: + description: The scheduling constraints on dm-master pods. + 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 + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by + this field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. This + field is beta-level and is only honored when + PodAffinityNamespaceSelector feature is enabled. + 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 a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected + by namespaceSelector. null or empty namespaces + list and null namespaceSelector 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 + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces field. + null selector and null or empty namespaces list + means "this pod's namespace". An empty selector + ({}) matches all namespaces. This field is beta-level + and is only honored when PodAffinityNamespaceSelector + feature is enabled. + 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 a static list + of namespace names that the term applies to. The + term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces list + and null namespaceSelector 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 + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by + this field and the ones listed in the namespaces + field. null selector and null or empty namespaces + list means "this pod's namespace". An empty + selector ({}) matches all namespaces. This + field is beta-level and is only honored when + PodAffinityNamespaceSelector feature is enabled. + 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 a static list + of namespace names that the term applies to. + The term is applied to the union of the namespaces + listed in this field and the ones selected + by namespaceSelector. null or empty namespaces + list and null namespaceSelector 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 + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied + to the union of the namespaces selected by this + field and the ones listed in the namespaces field. + null selector and null or empty namespaces list + means "this pod's namespace". An empty selector + ({}) matches all namespaces. This field is beta-level + and is only honored when PodAffinityNamespaceSelector + feature is enabled. + 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 a static list + of namespace names that the term applies to. The + term is applied to the union of the namespaces + listed in this field and the ones selected by + namespaceSelector. null or empty namespaces list + and null namespaceSelector 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 + annotations: + additionalProperties: + type: string + description: Annotations specifies the annotations to attach to + pods the operator creates for the dm-master cluster. The "dm-master.version" + annotation is reserved for the internal use of the dm-master + operator. + type: object + antiAffinity: + description: '**DEPRECATED**. Use Affinity instead.' + type: boolean + dm-masterEnv: + description: List of environment variables to set in the dm-master + container. This is used to configure dm-master process. dm-master + cluster cannot be created, when bad environement variables are + provided. Do not overwrite any flags used to bootstrap the cluster + (for example `--initial-cluster` flag). This field cannot be + updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels[''<KEY>'']`, + `metadata.annotations[''<KEY>'']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + labels: + additionalProperties: + type: string + description: Labels specifies the labels to attach to pods the + operator creates for the dm-master cluster. "app" and "dm-master_*" + labels are reserved for the internal use of the dm-master operator. + Do not overwrite them. + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector specifies a map of key-value pairs. + For the pod to be eligible to run on a node, the node must have + each of the indicated key-value pairs as labels. + type: object + persistentVolumeClaimSpec: + description: PersistentVolumeClaimSpec is the spec to describe + PVC for the dm-master container This field is optional. If no + PVC spec, dm-master container will use emptyDir as volume Note. + This feature is in alpha stage. It is currently only used as + non-stable storage, not the stable storage. Future work need + to make it used as stable storage. + 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) + * An existing PVC (PersistentVolumeClaim) 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 AnyVolumeDataSource + feature gate is enabled, this field will always have the + same contents as the DataSourceRef field.' + 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 + dataSourceRef: + description: 'Specifies the object from which to populate + the volume with data, if a non-empty volume is desired. + This may be any local object from a non-empty API group + (non core object) or a PersistentVolumeClaim object. When + this field is specified, volume binding will only succeed + if the type of the specified object matches some installed + volume populator or dynamic provisioner. This field will + replace the functionality of the DataSource field and as + such if both fields are non-empty, they must have the same + value. For backwards compatibility, both fields (DataSource + and DataSourceRef) will be set to the same value automatically + if one of them is empty and the other is non-empty. There + are two important differences between DataSource and DataSourceRef: + * While DataSource only allows two specific types of objects, + DataSourceRef allows any non-core object, as well as PersistentVolumeClaim + objects. * While DataSource ignores disallowed values (dropping + them), DataSourceRef preserves all values, and generates + an error if a disallowed value is specified. (Alpha) Using + this field requires the AnyVolumeDataSource feature gate + to be enabled.' + 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. If RecoverVolumeExpansionFailure feature + is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher + than capacity recorded in the status field of the claim. + 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-resources-containers/' + 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-resources-containers/' + 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 + resources: + description: Resources is the resource requirements for the dm-master + container. This field cannot be updated once the cluster is + created. + 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-resources-containers/' + 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-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext specifies the security context for + the entire pod More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context' + 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. Note that this field cannot be + set when spec.os.name is windows." + 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, "Always" is used. Note that + this field cannot be set when spec.os.name is windows.' + 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. Note that this field + cannot be set when spec.os.name is windows. + 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. + Note that this field cannot be set when spec.os.name is + windows. + 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. Note that this field cannot be set when + spec.os.name is windows. + 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. Note that this field cannot be set when spec.os.name + is windows. + 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. + Note that this field cannot be set when spec.os.name is + windows. + 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. Note that this field cannot + be set when spec.os.name is windows. + 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. Note that this field cannot be set when + spec.os.name is linux. + 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 + hostProcess: + description: HostProcess determines if a container should + be run as a 'Host Process' container. This field is + alpha-level and will only be honored by components that + enable the WindowsHostProcessContainers feature flag. + Setting this field without the feature flag will result + in errors when validating the Pod. All of a Pod's containers + must have the same effective HostProcess value (it is + not allowed to have a mix of HostProcess containers + and non-HostProcess containers). In addition, if HostProcess + is true then HostNetwork must also be set to true. + type: boolean + 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 + tolerations: + description: Tolerations specifies the pod's tolerations. + 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 + type: object + re_generate: + default: false + description: ReGenerate defines if delete the old_deployment and create + a new deployment + type: boolean + replicas: + default: 3 + description: Replicas is the expected size of the ms-master. The ds-master-operator + will eventually make the size of the running equal to the expected + size. The vaild range of the size is from 1 to 7. + maximum: 7 + minimum: 1 + type: integer + repository: + default: apache/dolphinscheduler-master + description: Repository is the name of the repository that hosts ds + container images. It should be direct clone of the repository in + official By default, it is `apache/dolphinscheduler-master`. + type: string + version: + default: 3.0.0-alpha + description: Version is the expected version of the ds cluster. The + ds-operator will eventually make the ds cluster version equal to + the expected version. If version is not set, default is "3.0.0-alpha". + type: string + required: + - datasource + - replicas + type: object + status: + description: DSAlertStatus defines the observed state of DSAlert + properties: + conditions: + description: Condition keeps track of all cluster conditions, if they + exist. + items: + description: DsCondition represents one current condition of a ds + cluster. A condition might not show up if it is not happening. + For example, if a cluster is not upgrading, the Upgrading condition + would not show up. If a cluster is upgrading and encountered a + problem that prevents the upgrade, the Upgrading condition's status + will would be False and communicate the problem back. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + type: string + lastUpdateTime: + description: The last time this condition was updated. + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of cluster condition. + type: string + required: + - status + - type + type: object + type: array + controlPaused: + default: false + description: ControlPaused indicates the operator pauses the control + of the cluster. + type: boolean + members: + description: Members are the dsMaster members in the cluster + properties: + ready: + description: Ready are the dsMaster members that are ready to + serve requests The member names are the same as the dsMaster + pod names + items: + type: string + type: array + unready: + description: Unready are the etcd members not ready to serve requests + items: + type: string + type: array + type: object + phase: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file Phase is the cluster running phase' + enum: + - "" + - Creating + - Running + - Failed + - Finished + type: string + replicas: + default: 0 + description: Replicas is the current size of the cluster + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 578c9e7..3089d02 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -5,6 +5,7 @@ resources: - bases/ds.apache.dolphinscheduler.dev_dsmasters.yaml - bases/ds.apache.dolphinscheduler.dev_dsworkers.yaml - bases/ds.apache.dolphinscheduler.dev_dsalerts.yaml +- bases/ds.apache.dolphinscheduler.dev_dsapis.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -13,6 +14,7 @@ patchesStrategicMerge: #- patches/webhook_in_dsmasters.yaml #- patches/webhook_in_dsworkers.yaml #- patches/webhook_in_dsalerts.yaml +#- patches/webhook_in_dsapis.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -20,6 +22,7 @@ patchesStrategicMerge: #- patches/cainjection_in_dsmasters.yaml #- patches/cainjection_in_dsworkers.yaml #- patches/cainjection_in_dsalerts.yaml +#- patches/cainjection_in_dsapis.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_dsalerts.yaml b/config/crd/patches/cainjection_in_dsalerts.yaml new file mode 100644 index 0000000..014aed7 --- /dev/null +++ b/config/crd/patches/cainjection_in_dsalerts.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: dsalerts.ds.apache.dolphinscheduler.dev diff --git a/config/crd/patches/webhook_in_dsalerts.yaml b/config/crd/patches/webhook_in_dsalerts.yaml new file mode 100644 index 0000000..2a239f4 --- /dev/null +++ b/config/crd/patches/webhook_in_dsalerts.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: dsalerts.ds.apache.dolphinscheduler.dev +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/ds/alert/ds-alert-deployment.yaml b/config/ds/alert/ds-alert-deployment.yaml deleted file mode 100644 index 627e1d6..0000000 --- a/config/ds/alert/ds-alert-deployment.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: ds-alert-deployment - namespace: ds -spec: - replicas: 1 - selector: - matchLabels: - app: ds-alert - template: - metadata: - labels: - app: ds-alert - spec: - containers: - - name: ds-alert - image: apache/dolphinscheduler-alert-server:3.0.0-alpha - imagePullPolicy: "IfNotPresent" - ports: - - containerPort: 50052 - env: - - name: SPRING_DATASOURCE_DRIVER_CLASS_NAME - value: org.postgresql.Driver - - name: SPRING_DATASOURCE_URL - value: "jdbc:postgresql://172.17.0.4:5432/dolphinscheduler" - - name: SPRING_DATASOURCE_USERNAME - value: "postgresadmin" - - name: SPRING_DATASOURCE_PASSWORD - value: "admin12345" \ No newline at end of file diff --git a/config/ds/alert/ds-alert-service.yaml b/config/ds/alert/ds-alert-service.yaml deleted file mode 100644 index 21bc518..0000000 --- a/config/ds/alert/ds-alert-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: ds-alert-service - namespace: ds -spec: - type: NodePort - ports: - - protocol: TCP - port: 50052 - targetPort: 50052 - selector: - app: ds-alert - - - - diff --git a/config/rbac/dsalert_editor_role.yaml b/config/rbac/dsalert_editor_role.yaml new file mode 100644 index 0000000..b0c7a8a --- /dev/null +++ b/config/rbac/dsalert_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit dsalerts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dsalert-editor-role +rules: +- apiGroups: + - ds.apache.dolphinscheduler.dev + resources: + - dsalerts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ds.apache.dolphinscheduler.dev + resources: + - dsalerts/status + verbs: + - get diff --git a/config/rbac/dsalert_viewer_role.yaml b/config/rbac/dsalert_viewer_role.yaml new file mode 100644 index 0000000..a365e12 --- /dev/null +++ b/config/rbac/dsalert_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view dsalerts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dsalert-viewer-role +rules: +- apiGroups: + - ds.apache.dolphinscheduler.dev + resources: + - dsalerts + verbs: + - get + - list + - watch +- apiGroups: + - ds.apache.dolphinscheduler.dev + resources: + - dsalerts/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 9ef8743..5b6627c 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -31,6 +31,32 @@ rules: - get - patch - update +- apiGroups: + - ds.apache.dolphinscheduler.dev + resources: + - dsapis + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ds.apache.dolphinscheduler.dev + resources: + - dsapis/finalizers + verbs: + - update +- apiGroups: + - ds.apache.dolphinscheduler.dev + resources: + - dsapis/status + verbs: + - get + - patch + - update - apiGroups: - ds.apache.dolphinscheduler.dev resources: diff --git a/config/samples/ds_v1alpha1_dsalert.yaml b/config/samples/ds_v1alpha1_dsalert.yaml new file mode 100644 index 0000000..56c5647 --- /dev/null +++ b/config/samples/ds_v1alpha1_dsalert.yaml @@ -0,0 +1,16 @@ +apiVersion: ds.apache.dolphinscheduler.dev/v1alpha1 +kind: DSAlert +metadata: + name: ds-alert + namespace: ds + labels: + app: ds-alert +spec: + replicas: 1 + version: 3.0.0-alpha + repository: apache/dolphinscheduler-alert-server + datasource: + drive_name: "org.postgresql.Driver" + url: "jdbc:postgresql://172.17.0.4:5432/dolphinscheduler" + username: "postgresadmin" + password: "admin12345" diff --git a/controllers/alert_reconcile.go b/controllers/alert_reconcile.go index 8326f23..0f6d0b1 100644 --- a/controllers/alert_reconcile.go +++ b/controllers/alert_reconcile.go @@ -27,18 +27,18 @@ import ( func createAlertService(cluster *dsv1alpha1.DSAlert) *corev1.Service { service := corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: "ds-alert-service", + Name: dsv1alpha1.DsAlertServiceValue, Namespace: cluster.Namespace, - Labels: map[string]string{dsv1alpha1.DsAppName: "ds-alert-service"}, + Labels: map[string]string{dsv1alpha1.DsAppName: dsv1alpha1.DsAlertServiceValue}, }, Spec: corev1.ServiceSpec{ - Selector: map[string]string{dsv1alpha1.DsAppName: "ds-alert"}, + Selector: map[string]string{dsv1alpha1.DsAppName: dsv1alpha1.DsAlert}, Ports: []corev1.ServicePort{ { Protocol: corev1.ProtocolTCP, - Port: *int32Ptr(int32(50052)), + Port: *int32Ptr(int32(dsv1alpha1.DsAlertPort)), TargetPort: intstr.IntOrString{ - IntVal: 50052, + IntVal: dsv1alpha1.DsAlertPort, }, }, }, @@ -50,25 +50,25 @@ func createAlertService(cluster *dsv1alpha1.DSAlert) *corev1.Service { func createAlertDeployment(cluster *dsv1alpha1.DSAlert) *v1.Deployment { alertDeployment := v1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "ds-alert-deployment", - Namespace: "ds", + Name: dsv1alpha1.DsAlertDeploymentValue, + Namespace: cluster.Namespace, }, Spec: v1.DeploymentSpec{ Replicas: int32Ptr(int32(cluster.Spec.Replicas)), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ - "app": "ds-alert", + dsv1alpha1.DsAppName: dsv1alpha1.DsAlert, }, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ - "app": "ds-alert", + dsv1alpha1.DsAppName: dsv1alpha1.DsAlert, }, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{{ - Name: "ds-alert", + Name: dsv1alpha1.DsAlert, Image: ImageName(cluster.Spec.Repository, cluster.Spec.Version), ImagePullPolicy: corev1.PullIfNotPresent, Env: []corev1.EnvVar{ @@ -90,7 +90,7 @@ func createAlertDeployment(cluster *dsv1alpha1.DSAlert) *v1.Deployment { }, }, Ports: []corev1.ContainerPort{{ - ContainerPort: 50052, + ContainerPort: dsv1alpha1.DsAlertPort, }, }, }, diff --git a/controllers/alert_reconcile.go b/controllers/api_reconcile.go similarity index 72% copy from controllers/alert_reconcile.go copy to controllers/api_reconcile.go index 8326f23..0062c14 100644 --- a/controllers/alert_reconcile.go +++ b/controllers/api_reconcile.go @@ -24,22 +24,24 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" ) -func createAlertService(cluster *dsv1alpha1.DSAlert) *corev1.Service { +func createApiService(cluster *dsv1alpha1.DSApi) *corev1.Service { service := corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: "ds-alert-service", + Name: dsv1alpha1.DsApiServiceValue, Namespace: cluster.Namespace, - Labels: map[string]string{dsv1alpha1.DsAppName: "ds-alert-service"}, + Labels: map[string]string{dsv1alpha1.DsAppName: dsv1alpha1.DsApiServiceValue}, }, Spec: corev1.ServiceSpec{ - Selector: map[string]string{dsv1alpha1.DsAppName: "ds-alert"}, + Type: corev1.ServiceTypeNodePort, + Selector: map[string]string{dsv1alpha1.DsAppName: dsv1alpha1.DsApi}, Ports: []corev1.ServicePort{ { Protocol: corev1.ProtocolTCP, - Port: *int32Ptr(int32(50052)), + Port: *int32Ptr(int32(dsv1alpha1.DsApiPort)), TargetPort: intstr.IntOrString{ - IntVal: 50052, + IntVal: dsv1alpha1.DsApiPort, }, + NodePort: cluster.Spec.NodePort, }, }, }, @@ -47,28 +49,28 @@ func createAlertService(cluster *dsv1alpha1.DSAlert) *corev1.Service { return &service } -func createAlertDeployment(cluster *dsv1alpha1.DSAlert) *v1.Deployment { - alertDeployment := v1.Deployment{ +func createApiDeployment(cluster *dsv1alpha1.DSApi) *v1.Deployment { + ApiDeployment := v1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "ds-alert-deployment", - Namespace: "ds", + Name: dsv1alpha1.DsApiDeploymentValue, + Namespace: cluster.Namespace, }, Spec: v1.DeploymentSpec{ Replicas: int32Ptr(int32(cluster.Spec.Replicas)), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ - "app": "ds-alert", + dsv1alpha1.DsAppName: dsv1alpha1.DsApi, }, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ - "app": "ds-alert", + dsv1alpha1.DsAppName: dsv1alpha1.DsApi, }, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{{ - Name: "ds-alert", + Name: dsv1alpha1.DsApi, Image: ImageName(cluster.Spec.Repository, cluster.Spec.Version), ImagePullPolicy: corev1.PullIfNotPresent, Env: []corev1.EnvVar{ @@ -90,7 +92,7 @@ func createAlertDeployment(cluster *dsv1alpha1.DSAlert) *v1.Deployment { }, }, Ports: []corev1.ContainerPort{{ - ContainerPort: 50052, + ContainerPort: dsv1alpha1.DsApiPort, }, }, }, @@ -99,9 +101,5 @@ func createAlertDeployment(cluster *dsv1alpha1.DSAlert) *v1.Deployment { }, }, } - return &alertDeployment -} - -func int32Ptr(i int32) *int32 { - return &i + return &ApiDeployment } diff --git a/controllers/dsalert_controller.go b/controllers/dsalert_controller.go new file mode 100644 index 0000000..787585b --- /dev/null +++ b/controllers/dsalert_controller.go @@ -0,0 +1,221 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controllers + +import ( + "context" + dsv1alpha1 "dolphinscheduler-operator/api/v1alpha1" + v1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "time" +) + +// DSAlertReconciler reconciles a DSAlert object +var ( + alertLogger = ctrl.Log.WithName("DSAlert-controller") +) + +type DSAlertReconciler struct { + client.Client + Scheme *runtime.Scheme + Recorder record.EventRecorder +} + +//+kubebuilder:rbac:groups=ds.apache.dolphinscheduler.dev,resources=dsalerts,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=ds.apache.dolphinscheduler.dev,resources=dsalerts/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=ds.apache.dolphinscheduler.dev,resources=dsalerts/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// the DSAlert object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile +func (r *DSAlertReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + + alertLogger.Info("dmAlert start reconcile logic") + defer alertLogger.Info("dmAlert Reconcile end ---------------------------------------------") + + cluster := &dsv1alpha1.DSAlert{} + + if err := r.Client.Get(ctx, req.NamespacedName, cluster); err != nil { + if errors.IsNotFound(err) { + r.Recorder.Event(cluster, corev1.EventTypeWarning, "dsAlert is not Found", "dsAlert is not Found") + return ctrl.Result{}, nil + } + return ctrl.Result{}, err + } + desired := cluster.DeepCopy() + + // Handler finalizer + // examine DeletionTimestamp to determine if object is under deletion + if cluster.ObjectMeta.DeletionTimestamp.IsZero() { + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. This is equivalent + // registering our finalizer. + if !controllerutil.ContainsFinalizer(desired, dsv1alpha1.FinalizerName) { + controllerutil.AddFinalizer(desired, dsv1alpha1.FinalizerName) + if err := r.Update(ctx, desired); err != nil { + return ctrl.Result{}, err + } + } + } else { + // The object is being deleted + + if controllerutil.ContainsFinalizer(desired, dsv1alpha1.FinalizerName) { + // our finalizer is present, so lets handle any external dependency + if err := r.ensureDSAlertDeleted(ctx, cluster); err != nil { + return ctrl.Result{}, err + } + + // remove our finalizer from the list and update it. + controllerutil.RemoveFinalizer(desired, dsv1alpha1.FinalizerName) + if err := r.Update(ctx, desired); err != nil { + return ctrl.Result{}, err + } + } + // Stop reconciliation as the item is being deleted + return ctrl.Result{}, nil + } + + if cluster.Spec.Paused { + alertLogger.Info("ds-alert control has been paused: ", "ds-alert-name", cluster.Name) + desired.Status.ControlPaused = true + if err := r.Status().Patch(ctx, desired, client.MergeFrom(cluster)); err != nil { + return ctrl.Result{}, err + } + r.Recorder.Event(cluster, corev1.EventTypeNormal, "the spec status is paused", "do nothing") + return ctrl.Result{}, nil + } + + // 1. First time we see the ds-master-cluster, initialize it + if cluster.Status.Phase == dsv1alpha1.DsPhaseNone { + desired.Status.Phase = dsv1alpha1.DsPhaseCreating + alertLogger.Info("phase had been changed from none ---> creating") + err := r.Client.Status().Patch(ctx, desired, client.MergeFrom(cluster)) + return ctrl.Result{RequeueAfter: 100 * time.Millisecond}, err + } + + //2 ensure the alert service + alertLogger.Info("Ensuring alert service") + + if err := r.ensureAlertService(ctx, cluster); err != nil { + return ctrl.Result{Requeue: true}, nil + } + + if requeue, err := r.ensureAlertDeployment(ctx, cluster); err != nil { + return ctrl.Result{Requeue: false}, err + } else { + if !requeue { + return ctrl.Result{Requeue: false}, nil + } + } + + alertLogger.Info("******************************************************") + desired.Status.Phase = dsv1alpha1.DsPhaseNone + if err := r.Update(ctx, desired); err != nil { + return ctrl.Result{}, err + } + return ctrl.Result{Requeue: false}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *DSAlertReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&dsv1alpha1.DSAlert{}). + Owns(&v1.Deployment{}). + Owns(&corev1.Service{}). + Owns(&corev1.Pod{}). + Complete(r) +} + +func (r *DSAlertReconciler) ensureDSAlertDeleted(ctx context.Context, DSAlert *dsv1alpha1.DSAlert) error { + if err := r.Client.Delete(ctx, DSAlert, client.PropagationPolicy(metav1.DeletePropagationOrphan)); err != nil { + return err + } + return nil +} + +func (r *DSAlertReconciler) ensureAlertService(ctx context.Context, cluster *dsv1alpha1.DSAlert) error { + // 1. Client service + service := &corev1.Service{} + namespacedName := types.NamespacedName{Namespace: cluster.Namespace, Name: dsv1alpha1.DsAlertServiceValue} + if err := r.Client.Get(ctx, namespacedName, service); err != nil { + // Local cache not found + logger.Info("get service error") + if apierrors.IsNotFound(err) { + service = createAlertService(cluster) + if err := controllerutil.SetControllerReference(cluster, service, r.Scheme); err != nil { + logger.Info("create alert service error") + return err + } + // Remote may already exist, so we will return err, for the next time, this code will not execute + if err := r.Client.Create(ctx, service); err != nil { + logger.Info("create alert service error1") + return err + } + logger.Info("the alert service had been created") + } + } + return nil +} + +func (r *DSAlertReconciler) ensureAlertDeployment(ctx context.Context, cluster *dsv1alpha1.DSAlert) (bool, error) { + deployment := &v1.Deployment{} + deploymentNamespaceName := types.NamespacedName{Namespace: cluster.Namespace, Name: dsv1alpha1.DsAlertDeploymentValue} + if err := r.Client.Get(ctx, deploymentNamespaceName, deployment); err != nil { + if apierrors.IsNotFound(err) { + deployment = createAlertDeployment(cluster) + } + if err := controllerutil.SetControllerReference(cluster, deployment, r.Scheme); err != nil { + return true, err + } + if err := r.Client.Create(ctx, deployment); err == nil { + return false, nil + } else { + return true, err + } + } else { + err := r.updateAlertDeployment(ctx, deployment, cluster) + if err != nil { + return false, err + } + } + + return true, nil +} + +//only notice the property of replicas and image and version +func (r *DSAlertReconciler) updateAlertDeployment(ctx context.Context, deployment *v1.Deployment, cluster *dsv1alpha1.DSAlert) error { + deployment.Spec.Replicas = int32Ptr(int32(cluster.Spec.Replicas)) + deployment.Spec.Template.Spec.Containers[0].Image = ImageName(cluster.Spec.Repository, cluster.Spec.Version) + if err := r.Client.Update(ctx, deployment); err != nil { + return err + } + return nil +} diff --git a/controllers/dsmaster_controller.go b/controllers/dsmaster_controller.go index 559d61b..f863d45 100644 --- a/controllers/dsmaster_controller.go +++ b/controllers/dsmaster_controller.go @@ -43,7 +43,6 @@ import ( const ( dsMasterLabel = "ds-master" dsServiceLabel = "ds-operator-service" - dsServiceName = "ds-operator-service" ) var ( @@ -54,7 +53,7 @@ var ( type DSMasterReconciler struct { client.Client Scheme *runtime.Scheme - Recorder record.EventRecorder + recorder record.EventRecorder clusters sync.Map resyncCh chan event.GenericEvent } @@ -79,7 +78,7 @@ func (r *DSMasterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if err := r.Client.Get(ctx, req.NamespacedName, cluster); err != nil { if errors.IsNotFound(err) { - r.Recorder.Event(cluster, corev1.EventTypeWarning, "dsMaster is not Found", "dsMaster is not Found") + r.recorder.Event(cluster, corev1.EventTypeWarning, "dsMaster is not Found", "dsMaster is not Found") return ctrl.Result{}, nil } return ctrl.Result{}, err @@ -125,7 +124,7 @@ func (r *DSMasterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c if err := r.Status().Patch(ctx, desired, client.MergeFrom(cluster)); err != nil { return ctrl.Result{}, err } - r.Recorder.Event(cluster, corev1.EventTypeNormal, "the spec status is paused", "do nothing") + r.recorder.Event(cluster, corev1.EventTypeNormal, "the spec status is paused", "do nothing") return ctrl.Result{}, nil } @@ -179,7 +178,7 @@ func (r *DSMasterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c func (r *DSMasterReconciler) SetupWithManager(mgr ctrl.Manager) error { r.clusters = sync.Map{} r.resyncCh = make(chan event.GenericEvent) - r.Recorder = mgr.GetEventRecorderFor("master-controller") + r.recorder = mgr.GetEventRecorderFor("master-controller") filter := &Predicate{} return ctrl.NewControllerManagedBy(mgr). @@ -217,7 +216,7 @@ func (r *DSMasterReconciler) ensureScaled(ctx context.Context, cluster *dsv1alph if len(ms) < cluster.Spec.Replicas { err = r.createMember(ctx, cluster) if err != nil { - r.Recorder.Event(cluster, corev1.EventTypeWarning, "cannot create the new ds-master pod", "the ds-master pod had been created failed") + r.recorder.Event(cluster, corev1.EventTypeWarning, "cannot create the new ds-master pod", "the ds-master pod had been created failed") return true, err } // Cluster modified, next reconcile will enter r.ensureMembers() diff --git a/controllers/dsworker_controller.go b/controllers/dsworker_controller.go index 00a97af..e16abc7 100644 --- a/controllers/dsworker_controller.go +++ b/controllers/dsworker_controller.go @@ -55,7 +55,6 @@ var ( // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by // the DSWorker object against the actual cluster state, and then // perform operations to make the cluster state reflect the state specified by // the user. @@ -157,6 +156,7 @@ func (r *DSWorkerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c func (r *DSWorkerReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&dsv1alpha1.DSWorker{}). + Owns(&corev1.Pod{}). Complete(r) } diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 4e379b7..4baf528 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -65,7 +65,7 @@ var _ = BeforeSuite(func() { err = dsv1alpha1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) - //+kubebuilder:scaffold:scheme + //+kubebuilder:scaffold:Scheme k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) diff --git a/main.go b/main.go index 9f12997..56cc422 100644 --- a/main.go +++ b/main.go @@ -99,6 +99,13 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "DSAlert") os.Exit(1) } + if err = (&controllers.DSApiReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "DSApi") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
