Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to define schedule for bundles #450

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
70 changes: 70 additions & 0 deletions charts/fleet-crd/templates/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ spec:
nullable: true
type: array
type: object
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -556,6 +562,12 @@ spec:
namespace:
nullable: true
type: string
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -1060,6 +1072,12 @@ spec:
namespace:
nullable: true
type: string
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -1203,6 +1221,12 @@ spec:
namespace:
nullable: true
type: string
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -1328,6 +1352,11 @@ spec:
release:
nullable: true
type: string
scheduled:
type: boolean
scheduledAt:
nullable: true
type: string
syncGeneration:
nullable: true
type: integer
Expand Down Expand Up @@ -1763,6 +1792,12 @@ spec:
type: boolean
redeployAgentGeneration:
type: integer
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
type: object
status:
properties:
Expand Down Expand Up @@ -2961,6 +2996,12 @@ spec:
nullable: true
type: array
type: object
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -3227,6 +3268,12 @@ spec:
namespace:
nullable: true
type: string
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -3732,6 +3779,12 @@ spec:
namespace:
nullable: true
type: string
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -3875,6 +3928,12 @@ spec:
namespace:
nullable: true
type: string
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
serviceAccount:
nullable: true
type: string
Expand Down Expand Up @@ -4000,6 +4059,11 @@ spec:
release:
nullable: true
type: string
scheduled:
type: boolean
scheduledAt:
nullable: true
type: string
syncGeneration:
nullable: true
type: integer
Expand Down Expand Up @@ -4438,6 +4502,12 @@ spec:
type: boolean
redeployAgentGeneration:
type: integer
schedule:
nullable: true
type: string
scheduleWindow:
nullable: true
type: string
type: object
status:
properties:
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ require (
github.com/rancher/lasso v0.0.0-20210616224652-fc3ebd901c08
github.com/rancher/wrangler v0.8.4
github.com/rancher/wrangler-cli v0.0.0-20200815040857-81c48cf8ab43
github.com/robfig/cron v1.1.0 // indirect
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.3
github.com/stretchr/testify v1.7.0
Expand Down
59 changes: 59 additions & 0 deletions modules/agent/pkg/controllers/bundledeployment/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"sync"
"time"

"github.com/robfig/cron"

"github.com/rancher/fleet/modules/agent/pkg/deployer"
"github.com/rancher/fleet/modules/agent/pkg/trigger"
fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
Expand Down Expand Up @@ -90,6 +92,55 @@ func (h *handler) Cleanup(key string, bd *fleet.BundleDeployment) (*fleet.Bundle
}

func (h *handler) DeployBundle(bd *fleet.BundleDeployment, status fleet.BundleDeploymentStatus) (fleet.BundleDeploymentStatus, error) {

if bd.Spec.Options.Schedule != "" && status.ScheduledAt == "" {
ibrokethecloud marked this conversation as resolved.
Show resolved Hide resolved
cronSched, err := cron.ParseStandard(bd.Spec.Options.Schedule)
if err != nil {
return status, err
}
scheduledRun := cronSched.Next(time.Now())
after := scheduledRun.Sub(time.Now())
h.bdController.EnqueueAfter(bd.Namespace, bd.Name, after)
status.ScheduledAt = scheduledRun.Format(time.RFC3339)
status.Scheduled = true
condition.Cond(fleet.BundleScheduledCondition).SetStatusBool(&status, true)
condition.Cond(fleet.BundleDeploymentConditionDeployed).SetStatusBool(&status, false)
return status, nil
}

if bd.Spec.Options.Schedule != "" && status.ScheduledAt != "" {
ibrokethecloud marked this conversation as resolved.
Show resolved Hide resolved
nextRun, err := time.Parse(time.RFC3339, status.ScheduledAt)
if err != nil {
return status, err
}
window := fleet.DefaultWindow
if bd.Spec.Options.ScheduleWindow != "" {
window = bd.Spec.Options.ScheduleWindow
}

windowDuration, err := time.ParseDuration(window)
if err != nil {
return status, err
}

if err != nil {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

There is a duplicated error check here

return status, err
}
ibrokethecloud marked this conversation as resolved.
Show resolved Hide resolved
if nextRun.After(time.Now()) {
after := nextRun.Sub(time.Now())
h.bdController.EnqueueAfter(bd.Namespace, bd.Name, after)
return status, nil
}

// case of disconnected agent during the actual window //
if nextRun.Add(windowDuration).Before(time.Now()) {
// clean up scheduled at to allow object to fall through scheduling
status.ScheduledAt = ""
status.Scheduled = false
return status, nil
}
}

depBundles, ok, err := h.checkDependency(bd)
if err != nil {
return status, err
Expand All @@ -108,6 +159,7 @@ func (h *handler) DeployBundle(bd *fleet.BundleDeployment, status fleet.BundleDe
if err != nil {
return status, err
}
status.Scheduled = false
status.Release = release
status.AppliedDeploymentID = bd.Spec.DeploymentID
return status, nil
Expand Down Expand Up @@ -219,6 +271,11 @@ func (h *handler) cleanupOldAgent(modifiedStatuses []fleet.ModifiedStatus) error
}

func (h *handler) MonitorBundle(bd *fleet.BundleDeployment, status fleet.BundleDeploymentStatus) (fleet.BundleDeploymentStatus, error) {

if status.Scheduled {
return status, nil
}

if bd.Spec.DeploymentID != status.AppliedDeploymentID {
return status, nil
}
Expand Down Expand Up @@ -271,6 +328,8 @@ func readyError(status fleet.BundleDeploymentStatus) error {
if len(status.ModifiedStatus) > 0 {
msg = status.ModifiedStatus[0].String()
}
} else if status.Scheduled {
msg = "scheduled"
}

return errors.New(msg)
Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/fleet.cattle.io/v1alpha1/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ var (
}
)

const DefaultWindow = "1h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should put this in the Helm chart.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickgerace do you want to expose this default Window as an option for the agent controller? similar to checkin interval?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes!


type BundleState string

// +genclient
Expand Down Expand Up @@ -134,6 +136,7 @@ var (
BundleConditionReady = "Ready"
BundleDeploymentConditionReady = "Ready"
BundleDeploymentConditionDeployed = "Deployed"
BundleScheduledCondition = "Scheduled"
)

type BundleStatus struct {
Expand Down Expand Up @@ -192,6 +195,8 @@ type BundleDeploymentOptions struct {
ForceSyncGeneration int64 `json:"forceSyncGeneration,omitempty"`
YAML *YAMLOptions `json:"yaml,omitempty"`
Diff *DiffOptions `json:"diff,omitempty"`
Schedule string `json:"schedule,omitempty"`
ScheduleWindow string `json:"scheduleWindow,omitempty"`
}

type DiffOptions struct {
Expand Down Expand Up @@ -279,10 +284,12 @@ type BundleDeploymentStatus struct {
Release string `json:"release,omitempty"`
Ready bool `json:"ready,omitempty"`
NonModified bool `json:"nonModified,omitempty"`
Scheduled bool `json:"scheduled,omitempty"`
NonReadyStatus []NonReadyStatus `json:"nonReadyStatus,omitempty"`
ModifiedStatus []ModifiedStatus `json:"modifiedStatus,omitempty"`
Display BundleDeploymentDisplay `json:"display,omitempty"`
SyncGeneration *int64 `json:"syncGeneration,omitempty"`
ScheduledAt string `json:"scheduledAt,omitempty"`
}

type BundleDeploymentDisplay struct {
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/fleet.cattle.io/v1alpha1/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ type ClusterSpec struct {
KubeConfigSecret string `json:"kubeConfigSecret,omitempty"`
RedeployAgentGeneration int64 `json:"redeployAgentGeneration,omitempty"`
AgentEnvVars []v1.EnvVar `json:"agentEnvVars,omitempty"`
Schedule string `json:"schedule,omitempty"`
ScheduleWindow string `json:"scheduleWindow,omitempty"`
AgentNamespace string `json:"agentNamespace,omitempty"`
}

Expand Down
15 changes: 15 additions & 0 deletions pkg/controllers/bundle/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bundle
import (
"context"
"sort"
"strings"

fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
fleetcontrollers "github.com/rancher/fleet/pkg/generated/controllers/fleet.cattle.io/v1alpha1"
Expand Down Expand Up @@ -232,6 +233,7 @@ func toRuntimeObjects(targets []*target.Target, bundle *fleet.Bundle) (result []
if target.Deployment == nil {
continue
}

dp := &fleet.BundleDeployment{
ObjectMeta: v1.ObjectMeta{
Name: target.Deployment.Name,
Expand All @@ -241,6 +243,19 @@ func toRuntimeObjects(targets []*target.Target, bundle *fleet.Bundle) (result []
Spec: target.Deployment.Spec,
}
dp.Spec.DependsOn = bundle.Spec.DependsOn

// Cluster level schedule and window takes priority over bundle specific schedule and window
// Ensure cluster schedule is always applied to all bundles
if !strings.HasPrefix(bundle.Name, "fleet-agent") {
if target.Cluster.Spec.Schedule != "" {
dp.Spec.Options.Schedule = target.Cluster.Spec.Schedule
}

if target.Cluster.Spec.ScheduleWindow != "" {
dp.Spec.Options.ScheduleWindow = target.Cluster.Spec.ScheduleWindow
}
}

result = append(result, dp)
}

Expand Down