Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
446c7c2
Add gronx lib for cron parsing
mobiusdickus Feb 15, 2025
b8c10dd
Add CronSchedule and StandardTime types
mobiusdickus Feb 15, 2025
7f1ca92
Update dummy app manifest
mobiusdickus Feb 15, 2025
3b77ef8
Add cron scheduling and standard time to sleep schedule operator
mobiusdickus Feb 15, 2025
78e915c
Update dummy app manifest with standard time spec
mobiusdickus Feb 15, 2025
4597321
Fix loading cron schedule
mobiusdickus Feb 15, 2025
624c4fb
Change StandardTime to DailyWindow
mobiusdickus Feb 16, 2025
1750a45
Fix required spec in sleepschedule crd
mobiusdickus Feb 17, 2025
4e5c828
Add kubebuild crd validation for DailyWindow and CronSchedule
mobiusdickus Feb 17, 2025
62e99e4
Fix basic test setup by adding new controller logic requirements
mobiusdickus Feb 17, 2025
b56341b
Add type back to schema spec
mobiusdickus Feb 18, 2025
13aea71
Update sample with new dailyWindow object
mobiusdickus Feb 18, 2025
85920c3
Fix intermittent status update failures due to stale resource versions
mobiusdickus Feb 18, 2025
9d4e29a
Add a clock util and SleepScheduleReconciler constructor for test abs…
mobiusdickus Feb 20, 2025
65b0198
Load the datetime obj directly to the SleepScheduleData
mobiusdickus Feb 21, 2025
96844e7
Add controller tests for new DailyWindow and CronSchedule spec requir…
mobiusdickus Feb 21, 2025
094b7ba
Add verbosity to the controller test output
mobiusdickus Feb 21, 2025
30a8fb7
Fix shouldSleep to handle weekly cron scheduling
mobiusdickus Feb 21, 2025
85d7daf
Add tests for weekday wake schedule and weekend sleep schedule
mobiusdickus Feb 21, 2025
ca513fd
Update README.md with new spec requirements
mobiusdickus Feb 21, 2025
695278b
Update and add more cron schedule tests
mobiusdickus Feb 22, 2025
a1255ce
Refactor sleep schedule controller tests
mobiusdickus Feb 24, 2025
bef1037
Refactor timezone to actually make optional and default to UTC as doc…
mobiusdickus Feb 24, 2025
a45b84a
Add comment on cron schedule implicit default wake state
mobiusdickus Feb 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 36 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,29 @@ As a common example, if you sleep all of your staging/ephemeral deployments for
helm install snorlax moonbeam/snorlax --create-namespace --namespace snorlax
```

2. Create your `SleepSchedule` resource to define the schedule for the deployment
2. Create your `SleepSchedule` resource to define the schedule for the deployment. You can use either a daily window or cron schedule:

**Using Daily Window:**
```yaml
# filename: your-app-sleep-schedule.yaml

apiVersion: snorlax.moonbeam.nyc/v1beta1
kind: SleepSchedule
metadata:
namespace: your-app-namespace
name: your-app
spec:
# Required fields
wakeTime: '8:00am'
sleepTime: '10:00pm'
dailyWindow:
wakeTime: '8:00am'
sleepTime: '10:00pm'
deployments:
- name: your-app-frontend
- name: your-app-db
- name: your-app-redis

# (optional, defaults to UTC) timezone for the sleep schedule using IANA format
timezone: 'America/New_York'

# (optional) the ingresses to update and point to the snorlax wake server,
# which wakes your deployment when a request is received while it's
# sleeping.
Expand All @@ -65,9 +70,33 @@ As a common example, if you sleep all of your staging/ephemeral deployments for
requires:
- deployment:
name: your-app-frontend
```

**Using Cron Schedule:**
```yaml
# filename: your-app-sleep-schedule.yaml
apiVersion: snorlax.moonbeam.nyc/v1beta1
kind: SleepSchedule
metadata:
namespace: your-app-namespace
name: your-app
spec:
# Required fields
cronSchedule:
wakeSchedule: '0 8 * * 1-5' # Wake at 8am on weekdays
sleepSchedule: '0 22 * * *' # Sleep at 10pm daily
deployments:
- name: your-app-frontend
- name: your-app-db
- name: your-app-redis

# (optional, defaults to UTC) the timezone to use for the input times above
# Optional fields
timezone: 'America/New_York'
ingresses:
- name: your-app-ingress
requires:
- deployment:
name: your-app-frontend
```

3. Apply the `SleepSchedule` resource
Expand All @@ -77,7 +106,8 @@ As a common example, if you sleep all of your staging/ephemeral deployments for

## Other features

- **Ingress controller awareness**: Snorlax determines which ingress controller you're running so it can create the correct ingress routes for sleep.
- **Flexible scheduling**: Support for both daily windows and cron expressions for more complex scheduling needs
- **Ingress controller awareness**: Snorlax determines which ingress controller you're running so it can create the correct ingress routes for sleep
- **Stays awake until next sleep cycle**: If a request is received during the sleep time, the deployment will stay awake until the next sleep cycle
- **Ignores ELB health checks**: Snorlax ignores health checks from ELBs so that they don't wake up the deployment

Expand Down Expand Up @@ -114,7 +144,6 @@ make dev-run
- Scale entire namespaces
- Sleep when no requests are received for a certain period of time
- Add support for custom wake & sleep actions (e.g. hit a webhook on wake)
- Add support for cron-style schedules (e.g. `0 8 * * *`)
- Add a button to manually wake up the deployment (instead of auto-waking on request)
- Custom image/gif for sleeping page
- Always sleeping mode, reset at a certain time of day
Expand Down
43 changes: 33 additions & 10 deletions charts/snorlax/templates/sleepschedule-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,42 @@ spec:
- name
type: object
type: array
sleepTime:
description: The time that the deployment will start sleeping
type: string
dailyWindow:
description: The daily times that the deployment will wake up and start sleeping
properties:
wakeTime:
description: The time that the deployment will wake up
type: string
sleepTime:
description: The time that the deployment will start sleeping
type: string
required:
- wakeTime
- sleepTime
type: object
cronSchedule:
description: The cron schedule that will be used to determine when the deployment will sleep/wake
properties:
wakeSchedule:
description: The cron schedule for when the deployment should wake up
type: string
sleepSchedule:
description: The cron schedule for when the deployment should go to sleep
type: string
required:
- wakeSchedule
- sleepSchedule
type: object
timezone:
description: The timezone that the input times are based in
type: string
wakeTime:
description: The time that the deployment will wake up
type: string
required:
- sleepTime
- timezone
- wakeTime
oneOf:
- required:
- dailyWindow
- timezone
- required:
- cronSchedule
- timezone
type: object
status:
description: SleepScheduleStatus defines the observed state of SleepSchedule
Expand Down
5 changes: 3 additions & 2 deletions dummy-app/k8s-manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ metadata:
namespace: default
name: dummy
spec:
wakeTime: '10:00am'
sleepTime: '10:01am'
dailyWindow:
wakeTime: '10:00am'
sleepTime: '10:01am'
timezone: 'America/New_York'
deployments:
- name: dummy-frontend
Expand Down
2 changes: 1 addition & 1 deletion operator/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ vet: ## Run go vet against code.

.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -v -ginkgo.v -coverprofile cover.out

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
Expand Down
30 changes: 25 additions & 5 deletions operator/api/v1beta1/sleepschedule_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,40 @@ import (
// 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.

type SleepScheduleSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

type DailyWindow struct {
// The time that the deployment will wake up
// +kubebuilder:validation:Required
WakeTime string `json:"wakeTime"`

// The time that the deployment will start sleeping
// +kubebuilder:validation:Required
SleepTime string `json:"sleepTime"`
}

// The timezone that the input times are based in
type CronSchedule struct {
// The cron schedule for when the deployment should wake up
// +kubebuilder:validation:Required
WakeSchedule string `json:"wakeSchedule"`

// The cron schedule for when the deployment should go to sleep
// +kubebuilder:validation:Required
SleepSchedule string `json:"sleepSchedule"`
}

// SleepScheduleSpec defines optional and required fields for SleepSchedule
// +kubebuilder:validation:XValidation:rule="has(self.dailyWindow) != has(self.cronSchedule)",message="exactly one of dailyWindow or cronSchedule must be specified"
type SleepScheduleSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

// The time that the deployment will wake up and start sleeping
DailyWindow *DailyWindow `json:"dailyWindow,omitempty"`

// The cron schedule that will be used to determine when the deployment will sleep/wake
CronSchedule *CronSchedule `json:"cronSchedule,omitempty"`

// The timezone that the input times are based in
// +optional
Timezone string `json:"timezone"`

// The deployments that will be slept/woken.
Expand Down
40 changes: 40 additions & 0 deletions operator/api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions operator/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook"

snorlaxv1beta1 "moonbeam-nyc/snorlax/api/v1beta1"
"moonbeam-nyc/snorlax/internal/controller"
controller "moonbeam-nyc/snorlax/internal/controller"
util "moonbeam-nyc/snorlax/internal/util"
//+kubebuilder:scaffold:imports
)

Expand Down Expand Up @@ -124,10 +125,11 @@ func main() {
os.Exit(1)
}

if err = (&controller.SleepScheduleReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
if err = controller.NewReconciler(
mgr.GetClient(),
mgr.GetScheme(),
util.RealTime{},
).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "SleepSchedule")
os.Exit(1)
}
Expand Down
44 changes: 34 additions & 10 deletions operator/config/crd/bases/snorlax.moonbeam.nyc_sleepschedules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,38 @@ spec:
metadata:
type: object
spec:
description: SleepScheduleSpec defines optional and required fields for
SleepSchedule
properties:
cronSchedule:
description: The cron schedule that will be used to determine when
the deployment will sleep/wake
properties:
sleepSchedule:
description: The cron schedule for when the deployment should
go to sleep
type: string
wakeSchedule:
description: The cron schedule for when the deployment should
wake up
type: string
required:
- sleepSchedule
- wakeSchedule
type: object
dailyWindow:
description: The time that the deployment will wake up and start sleeping
properties:
sleepTime:
description: The time that the deployment will start sleeping
type: string
wakeTime:
description: The time that the deployment will wake up
type: string
required:
- sleepTime
- wakeTime
type: object
deployments:
description: The deployments that will be slept/woken.
items:
Expand Down Expand Up @@ -75,20 +106,13 @@ spec:
- name
type: object
type: array
sleepTime:
description: The time that the deployment will start sleeping
type: string
timezone:
description: The timezone that the input times are based in
type: string
wakeTime:
description: The time that the deployment will wake up
type: string
required:
- sleepTime
- timezone
- wakeTime
type: object
x-kubernetes-validations:
- message: exactly one of dailyWindow or cronSchedule must be specified
rule: has(self.dailyWindow) != has(self.cronSchedule)
status:
description: SleepScheduleStatus defines the observed state of SleepSchedule
properties:
Expand Down
5 changes: 3 additions & 2 deletions operator/config/samples/snorlax_v1beta1_sleepschedule.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ metadata:
namespace: default
name: sleepschedule-sample
spec:
wakeTime: 7am
sleepTime: 11pm
dailyWindow:
wakeTime: 7am
sleepTime: 11pm
timezone: America/New_York
deploymentName: dummy-deployment
wakeReplicas: 3
Expand Down
1 change: 1 addition & 0 deletions operator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
)

require (
github.com/adhocore/gronx v1.19.5 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions operator/go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/adhocore/gronx v1.19.5 h1:cwIG4nT1v9DvadxtHBe6MzE+FZ1JDvAUC45U2fl4eSQ=
github.com/adhocore/gronx v1.19.5/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down
Loading