diff --git a/PROJECT b/PROJECT index 5fc2fe1f..93e37839 100644 --- a/PROJECT +++ b/PROJECT @@ -28,4 +28,13 @@ resources: webhooks: defaulting: true webhookVersion: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: mercari.com + group: autoscaling + kind: ScheduledScaling + path: github.com/mercari/tortoise/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go new file mode 100644 index 00000000..c771cf72 --- /dev/null +++ b/api/v1alpha1/groupversion_info.go @@ -0,0 +1,45 @@ +/* +MIT License + +Copyright (c) 2023 mercari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// Package v1alpha1 contains API Schema definitions for the autoscaling v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=autoscaling.mercari.com +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: "autoscaling.mercari.com", 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/scheduledscaling_types.go b/api/v1alpha1/scheduledscaling_types.go new file mode 100644 index 00000000..0cff0502 --- /dev/null +++ b/api/v1alpha1/scheduledscaling_types.go @@ -0,0 +1,117 @@ +/* +MIT License + +Copyright (c) 2023 mercari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + autoscalingv1beta3 "github.com/mercari/tortoise/api/v1beta3" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ScheduledScalingSpec defines the desired state of ScheduledScaling +type ScheduledScalingSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + /// Schedule RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" + Schedule Schedule `json:"schedule" protobuf:"bytes,1,name=schedule"` + + // TargetRef is the targets that need to be scheduled + TargetRefs TargetRefs `json:"targetRefs" protobuf:"bytes,2,name=targetRefs"` + + // Strategy describes how this ScheduledScaling scales the target workload. + // Currently, it only supports the static strategy. + Strategy Strategy `json:"strategy" protobuf:"bytes,3,name=strategy"` +} + +// ScheduledScalingStatus defines the observed state of ScheduledScaling +type ScheduledScalingStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + ScheduledScalingPhase ScheduledScalingPhase `json:"scheduledScalingPhase" protobuf:"bytes,1,name=scheduledScalingPhase"` +} + +type ScheduledScalingPhase string + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ScheduledScaling is the Schema for the scheduledscalings API +type ScheduledScaling struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ScheduledScalingSpec `json:"spec,omitempty"` + Status ScheduledScalingStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ScheduledScalingList contains a list of ScheduledScaling +type ScheduledScalingList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ScheduledScaling `json:"items"` +} + +type TargetRefs struct { + //Tortoise to be targeted for scheduled scaling + TortoiseName *string `json:"tortoiseName,omitempty" protobuf:"bytes,2,name=tortoiseName"` +} + +type Schedule struct { + /// RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" + // start of schedule + StartAt *string `json:"startAt" protobuf:"bytes,1,name=startAt"` + // end of schedule + FinishAt *string `json:"finishAt" protobuf:"bytes,2,name=finishAt"` +} + +type Strategy struct { + // Resource scaling requirements + // Static strategy receives the static value of the replica number and resource requests + // that users want to give to Pods during this ScheduledScaling is valid. + // This field is optional for the future when we add another strategy here though, + // until then this strategy is the only supported strategy + // you must set this. + // +optional + Static *Static `json:"static,omitempty" protobuf:"bytes,1,opt,name=static"` +} + +type Static struct { + // MinimumMinReplicas means the minimum MinReplicas that Tortoise gives to HPA during this ScheduledScaling is valid. + MinimumMinReplicas *int `json:"minimumMinReplica,omitempty" protobuf:"bytes,1,opt,name=minimumMinReplica"` + // MinAllowedResources means the minimum resource requests that Tortoise gives to each container. + MinAllocatedResources []autoscalingv1beta3.ContainerResourceRequests `json:"minAllocatedResourcesomitempty,omitempty" protobuf:"bytes,2,opt,name=minAllocatedResources"` +} + +func init() { + SchemeBuilder.Register(&ScheduledScaling{}, &ScheduledScalingList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000..733d24fc --- /dev/null +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,220 @@ +//go:build !ignore_autogenerated + +/* +MIT License + +Copyright (c) 2023 mercari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + + "github.com/mercari/tortoise/api/v1beta3" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Schedule) DeepCopyInto(out *Schedule) { + *out = *in + if in.StartAt != nil { + in, out := &in.StartAt, &out.StartAt + *out = new(string) + **out = **in + } + if in.FinishAt != nil { + in, out := &in.FinishAt, &out.FinishAt + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Schedule. +func (in *Schedule) DeepCopy() *Schedule { + if in == nil { + return nil + } + out := new(Schedule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScheduledScaling) DeepCopyInto(out *ScheduledScaling) { + *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 ScheduledScaling. +func (in *ScheduledScaling) DeepCopy() *ScheduledScaling { + if in == nil { + return nil + } + out := new(ScheduledScaling) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ScheduledScaling) 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 *ScheduledScalingList) DeepCopyInto(out *ScheduledScalingList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ScheduledScaling, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduledScalingList. +func (in *ScheduledScalingList) DeepCopy() *ScheduledScalingList { + if in == nil { + return nil + } + out := new(ScheduledScalingList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ScheduledScalingList) 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 *ScheduledScalingSpec) DeepCopyInto(out *ScheduledScalingSpec) { + *out = *in + in.Schedule.DeepCopyInto(&out.Schedule) + in.TargetRefs.DeepCopyInto(&out.TargetRefs) + in.Strategy.DeepCopyInto(&out.Strategy) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduledScalingSpec. +func (in *ScheduledScalingSpec) DeepCopy() *ScheduledScalingSpec { + if in == nil { + return nil + } + out := new(ScheduledScalingSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ScheduledScalingStatus) DeepCopyInto(out *ScheduledScalingStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduledScalingStatus. +func (in *ScheduledScalingStatus) DeepCopy() *ScheduledScalingStatus { + if in == nil { + return nil + } + out := new(ScheduledScalingStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Static) DeepCopyInto(out *Static) { + *out = *in + if in.MinimumMinReplicas != nil { + in, out := &in.MinimumMinReplicas, &out.MinimumMinReplicas + *out = new(int) + **out = **in + } + if in.MinAllocatedResources != nil { + in, out := &in.MinAllocatedResources, &out.MinAllocatedResources + *out = make([]v1beta3.ContainerResourceRequests, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Static. +func (in *Static) DeepCopy() *Static { + if in == nil { + return nil + } + out := new(Static) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Strategy) DeepCopyInto(out *Strategy) { + *out = *in + if in.Static != nil { + in, out := &in.Static, &out.Static + *out = new(Static) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Strategy. +func (in *Strategy) DeepCopy() *Strategy { + if in == nil { + return nil + } + out := new(Strategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetRefs) DeepCopyInto(out *TargetRefs) { + *out = *in + if in.TortoiseName != nil { + in, out := &in.TortoiseName, &out.TortoiseName + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetRefs. +func (in *TargetRefs) DeepCopy() *TargetRefs { + if in == nil { + return nil + } + out := new(TargetRefs) + in.DeepCopyInto(out) + return out +} diff --git a/config/crd/bases/autoscaling.mercari.com_scheduledscalings.yaml b/config/crd/bases/autoscaling.mercari.com_scheduledscalings.yaml new file mode 100644 index 00000000..de780d58 --- /dev/null +++ b/config/crd/bases/autoscaling.mercari.com_scheduledscalings.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: scheduledscalings.autoscaling.mercari.com +spec: + group: autoscaling.mercari.com + names: + kind: ScheduledScaling + listKind: ScheduledScalingList + plural: scheduledscalings + singular: scheduledscaling + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ScheduledScaling is the Schema for the scheduledscalings 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: ScheduledScalingSpec defines the desired state of ScheduledScaling + properties: + schedule: + description: / Schedule RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" + properties: + finishAt: + description: end of schedule + type: string + startAt: + description: / RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" + start of schedule + type: string + type: object + strategy: + description: Strategy describes how this ScheduledScaling scales the + target workload. Currently, it only supports the static strategy. + properties: + static: + description: Resource scaling requirements Static strategy receives + the static value of the replica number and resource requests + that users want to give to Pods during this ScheduledScaling + is valid. This field is optional for the future when we add + another strategy here though, until then this strategy is the + only supported strategy you must set this. + properties: + minAllocatedResourcesomitempty: + description: MinAllowedResources means the minimum resource + requests that Tortoise gives to each container. + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + resource: + 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: ResourceList is a set of (resource name, + quantity) pairs. + type: object + required: + - containerName + - resource + type: object + type: array + minimumMinReplica: + description: MinimumMinReplicas means the minimum MinReplicas + that Tortoise gives to HPA during this ScheduledScaling + is valid. + type: integer + type: object + type: object + targetRefs: + description: TargetRef is the targets that need to be scheduled + properties: + tortoiseName: + description: Tortoise to be targeted for scheduled scaling + type: string + type: object + required: + - schedule + - strategy + - targetRefs + type: object + status: + description: ScheduledScalingStatus defines the observed state of ScheduledScaling + properties: + scheduledScalingPhase: + type: string + required: + - scheduledScalingPhase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 2307667d..0ac52374 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,6 +3,7 @@ # It should be run by config/default resources: - bases/autoscaling.mercari.com_tortoises.yaml +- bases/autoscaling.mercari.com_scheduledscalings.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -10,12 +11,14 @@ patchesStrategicMerge: # patches here are for enabling the conversion webhook for each CRD - patches/webhook_in_tortoises.yaml #- patches/webhook_in_tortoises.yaml +#- patches/webhook_in_scheduledscalings.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD - patches/cainjection_in_tortoises.yaml #- patches/cainjection_in_tortoises.yaml +#- patches/cainjection_in_scheduledscalings.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_scheduledscalings.yaml b/config/crd/patches/cainjection_in_scheduledscalings.yaml new file mode 100644 index 00000000..6f18016a --- /dev/null +++ b/config/crd/patches/cainjection_in_scheduledscalings.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: scheduledscalings.autoscaling.mercari.com diff --git a/config/crd/patches/webhook_in_scheduledscalings.yaml b/config/crd/patches/webhook_in_scheduledscalings.yaml new file mode 100644 index 00000000..915eedb2 --- /dev/null +++ b/config/crd/patches/webhook_in_scheduledscalings.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: scheduledscalings.autoscaling.mercari.com +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index fe3e7558..0ba16255 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -76,6 +76,32 @@ rules: - patch - update - watch +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings/finalizers + verbs: + - update +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings/status + verbs: + - get + - patch + - update - apiGroups: - autoscaling.mercari.com resources: diff --git a/config/rbac/scheduledscaling_editor_role.yaml b/config/rbac/scheduledscaling_editor_role.yaml new file mode 100644 index 00000000..38e04028 --- /dev/null +++ b/config/rbac/scheduledscaling_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit scheduledscalings. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: scheduledscaling-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: tortoise + app.kubernetes.io/part-of: tortoise + app.kubernetes.io/managed-by: kustomize + name: scheduledscaling-editor-role +rules: +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings/status + verbs: + - get diff --git a/config/rbac/scheduledscaling_viewer_role.yaml b/config/rbac/scheduledscaling_viewer_role.yaml new file mode 100644 index 00000000..f8db1911 --- /dev/null +++ b/config/rbac/scheduledscaling_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view scheduledscalings. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: scheduledscaling-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: tortoise + app.kubernetes.io/part-of: tortoise + app.kubernetes.io/managed-by: kustomize + name: scheduledscaling-viewer-role +rules: +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings + verbs: + - get + - list + - watch +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings/status + verbs: + - get diff --git a/config/samples/autoscaling_v1alpha1_scheduledscaling.yaml b/config/samples/autoscaling_v1alpha1_scheduledscaling.yaml new file mode 100644 index 00000000..0c97abc7 --- /dev/null +++ b/config/samples/autoscaling_v1alpha1_scheduledscaling.yaml @@ -0,0 +1,12 @@ +apiVersion: autoscaling.mercari.com/v1alpha1 +kind: ScheduledScaling +metadata: + labels: + app.kubernetes.io/name: scheduledscaling + app.kubernetes.io/instance: scheduledscaling-sample + app.kubernetes.io/part-of: tortoise + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: tortoise + name: scheduledscaling-sample +spec: + # TODO(user): Add fields here diff --git a/controllers/scheduledscaling_controller.go b/controllers/scheduledscaling_controller.go new file mode 100644 index 00000000..1d7c582f --- /dev/null +++ b/controllers/scheduledscaling_controller.go @@ -0,0 +1,71 @@ +/* +MIT License + +Copyright (c) 2023 mercari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +package controllers + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + autoscalingv1alpha1 "github.com/mercari/tortoise/api/v1alpha1" +) + +// ScheduledScalingReconciler reconciles a ScheduledScaling object +type ScheduledScalingReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=autoscaling.mercari.com,resources=scheduledscalings,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=autoscaling.mercari.com,resources=scheduledscalings/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=autoscaling.mercari.com,resources=scheduledscalings/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. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ScheduledScaling 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/controller-runtime@v0.14.4/pkg/reconcile +func (r *ScheduledScalingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ScheduledScalingReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&autoscalingv1alpha1.ScheduledScaling{}). + Complete(r) +} diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 652ed475..ab9db268 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -44,6 +44,7 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" + autoscalingv1alpha1 "github.com/mercari/tortoise/api/v1alpha1" autoscalingv1beta3 "github.com/mercari/tortoise/api/v1beta3" . "github.com/onsi/ginkgo/v2" @@ -92,6 +93,9 @@ var _ = BeforeSuite(func() { err = v2.AddToScheme(scheme) Expect(err).NotTo(HaveOccurred()) + err = autoscalingv1alpha1.AddToScheme(scheme) + Expect(err).NotTo(HaveOccurred()) + //+kubebuilder:scaffold:scheme k8sClient, err = client.New(cfg, client.Options{Scheme: scheme}) diff --git a/go.mod b/go.mod index be38279f..b8c99451 100644 --- a/go.mod +++ b/go.mod @@ -59,13 +59,13 @@ require ( github.com/stretchr/testify v1.8.3 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.17.0 // indirect + golang.org/x/net v0.22.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.4.0 // indirect - golang.org/x/tools v0.9.1 // indirect + golang.org/x/tools v0.19.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index 36149e0f..ff8cef63 100644 --- a/go.sum +++ b/go.sum @@ -135,8 +135,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -144,8 +142,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -161,16 +159,16 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -179,8 +177,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= +golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main.go b/main.go index ee66638a..14a0b30f 100644 --- a/main.go +++ b/main.go @@ -47,6 +47,7 @@ import ( autoscalingv2 "github.com/mercari/tortoise/api/autoscaling/v2" v1 "github.com/mercari/tortoise/api/core/v1" + autoscalingv1alpha1 "github.com/mercari/tortoise/api/v1alpha1" autoscalingv1beta3 "github.com/mercari/tortoise/api/v1beta3" "github.com/mercari/tortoise/controllers" "github.com/mercari/tortoise/pkg/config" @@ -72,6 +73,7 @@ func init() { utilruntime.Must(autoscalingv1beta3.AddToScheme(scheme)) utilruntime.Must(autoscalingv1beta3.AddToScheme(scheme)) + utilruntime.Must(autoscalingv1alpha1.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } @@ -138,6 +140,7 @@ func main() { // after the manager stops then its usage might be unsafe. LeaderElectionReleaseOnCancel: true, }) + if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) @@ -196,6 +199,13 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "Tortoise") os.Exit(1) } + if err = (&controllers.ScheduledScalingReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ScheduledScaling") + os.Exit(1) + } //+kubebuilder:scaffold:builder hpaWebhook := autoscalingv2.New(tortoiseService, hpaService) diff --git a/manifests/crd/apiextensions.k8s.io_v1_customresourcedefinition_scheduledscalings.autoscaling.mercari.com.yaml b/manifests/crd/apiextensions.k8s.io_v1_customresourcedefinition_scheduledscalings.autoscaling.mercari.com.yaml new file mode 100644 index 00000000..1690afd6 --- /dev/null +++ b/manifests/crd/apiextensions.k8s.io_v1_customresourcedefinition_scheduledscalings.autoscaling.mercari.com.yaml @@ -0,0 +1,98 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: scheduledscalings.autoscaling.mercari.com +spec: + group: autoscaling.mercari.com + names: + kind: ScheduledScaling + listKind: ScheduledScalingList + plural: scheduledscalings + singular: scheduledscaling + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ScheduledScaling is the Schema for the scheduledscalings 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: ScheduledScalingSpec defines the desired state of ScheduledScaling + properties: + schedule: + description: / Schedule RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" + properties: + finishAt: + description: end of schedule + type: string + startAt: + description: / RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" start of schedule + type: string + type: object + strategy: + description: Strategy describes how this ScheduledScaling scales the target workload. Currently, it only supports the static strategy. + properties: + static: + description: Resource scaling requirements Static strategy receives the static value of the replica number and resource requests that users want to give to Pods during this ScheduledScaling is valid. This field is optional for the future when we add another strategy here though, until then this strategy is the only supported strategy you must set this. + properties: + minAllocatedResourcesomitempty: + description: MinAllowedResources means the minimum resource requests that Tortoise gives to each container. + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + resource: + 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: ResourceList is a set of (resource name, quantity) pairs. + type: object + required: + - containerName + - resource + type: object + type: array + minimumMinReplica: + description: MinimumMinReplicas means the minimum MinReplicas that Tortoise gives to HPA during this ScheduledScaling is valid. + type: integer + type: object + type: object + targetRefs: + description: TargetRef is the targets that need to be scheduled + properties: + tortoiseName: + description: Tortoise to be targeted for scheduled scaling + type: string + type: object + required: + - schedule + - strategy + - targetRefs + type: object + status: + description: ScheduledScalingStatus defines the observed state of ScheduledScaling + properties: + scheduledScalingPhase: + type: string + required: + - scheduledScalingPhase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/manifests/default/apiextensions.k8s.io_v1_customresourcedefinition_scheduledscalings.autoscaling.mercari.com.yaml b/manifests/default/apiextensions.k8s.io_v1_customresourcedefinition_scheduledscalings.autoscaling.mercari.com.yaml new file mode 100644 index 00000000..1690afd6 --- /dev/null +++ b/manifests/default/apiextensions.k8s.io_v1_customresourcedefinition_scheduledscalings.autoscaling.mercari.com.yaml @@ -0,0 +1,98 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: scheduledscalings.autoscaling.mercari.com +spec: + group: autoscaling.mercari.com + names: + kind: ScheduledScaling + listKind: ScheduledScalingList + plural: scheduledscalings + singular: scheduledscaling + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ScheduledScaling is the Schema for the scheduledscalings 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: ScheduledScalingSpec defines the desired state of ScheduledScaling + properties: + schedule: + description: / Schedule RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" + properties: + finishAt: + description: end of schedule + type: string + startAt: + description: / RFC3339 format e.g., "2006-01-02T15:04:05Z09:00" start of schedule + type: string + type: object + strategy: + description: Strategy describes how this ScheduledScaling scales the target workload. Currently, it only supports the static strategy. + properties: + static: + description: Resource scaling requirements Static strategy receives the static value of the replica number and resource requests that users want to give to Pods during this ScheduledScaling is valid. This field is optional for the future when we add another strategy here though, until then this strategy is the only supported strategy you must set this. + properties: + minAllocatedResourcesomitempty: + description: MinAllowedResources means the minimum resource requests that Tortoise gives to each container. + items: + properties: + containerName: + description: ContainerName is the name of target container. + type: string + resource: + 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: ResourceList is a set of (resource name, quantity) pairs. + type: object + required: + - containerName + - resource + type: object + type: array + minimumMinReplica: + description: MinimumMinReplicas means the minimum MinReplicas that Tortoise gives to HPA during this ScheduledScaling is valid. + type: integer + type: object + type: object + targetRefs: + description: TargetRef is the targets that need to be scheduled + properties: + tortoiseName: + description: Tortoise to be targeted for scheduled scaling + type: string + type: object + required: + - schedule + - strategy + - targetRefs + type: object + status: + description: ScheduledScalingStatus defines the observed state of ScheduledScaling + properties: + scheduledScalingPhase: + type: string + required: + - scheduledScalingPhase + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/manifests/default/rbac.authorization.k8s.io_v1_clusterrole_tortoise-manager-role.yaml b/manifests/default/rbac.authorization.k8s.io_v1_clusterrole_tortoise-manager-role.yaml index e17fbc50..2fd14d72 100644 --- a/manifests/default/rbac.authorization.k8s.io_v1_clusterrole_tortoise-manager-role.yaml +++ b/manifests/default/rbac.authorization.k8s.io_v1_clusterrole_tortoise-manager-role.yaml @@ -75,6 +75,32 @@ rules: - patch - update - watch +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings/finalizers + verbs: + - update +- apiGroups: + - autoscaling.mercari.com + resources: + - scheduledscalings/status + verbs: + - get + - patch + - update - apiGroups: - autoscaling.mercari.com resources: