Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions api/v1alpha1/function_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type FunctionStatus struct {

Git FunctionStatusGit `json:"git,omitempty"`
Deployment FunctionStatusDeployment `json:"deployment,omitempty"`
Middleware FunctionStatusMiddleware `json:"middleware,omitempty"`
}

type FunctionStatusGit struct {
Expand All @@ -93,6 +94,19 @@ type FunctionStatusDeployment struct {
Runtime string `json:"runtime,omitempty"`
}

type FunctionStatusMiddleware struct {
Current string `json:"current,omitempty"`
Available *string `json:"available,omitempty"`
AutoUpdate FunctionStatusMiddlewareAutoUpdate `json:"autoUpdate"`
PendingRebuild bool `json:"pendingRebuild"` // no omitempty to have it always shown
LastRebuild metav1.Time `json:"lastRebuild,omitempty"`
}

type FunctionStatusMiddlewareAutoUpdate struct {
Enabled bool `json:"enabled"` // no omitempty to have it always shown
Source string `json:"source,omitempty"`
}

// +kubebuilder:object:root=true

// FunctionList contains a list of Function.
Expand Down
38 changes: 38 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

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

24 changes: 24 additions & 0 deletions config/crd/bases/functions.dev_functions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,30 @@ spec:
resolvedBranch:
type: string
type: object
middleware:
properties:
autoUpdate:
properties:
enabled:
type: boolean
source:
type: string
required:
- enabled
type: object
available:
type: string
current:
type: string
lastRebuild:
format: date-time
type: string
pendingRebuild:
type: boolean
required:
- autoUpdate
- pendingRebuild
type: object
name:
type: string
required:
Expand Down
37 changes: 27 additions & 10 deletions internal/controller/function_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,18 +214,34 @@ func (r *FunctionReconciler) ensureDeployment(ctx context.Context, function *v1a
func (r *FunctionReconciler) handleMiddlewareUpdate(ctx context.Context, function *v1alpha1.Function, repo *git.Repository, metadata *funcfn.Function) error {
logger := log.FromContext(ctx)

functionDescribe, err := r.FuncCliManager.Describe(ctx, metadata.Name, function.Namespace)
if err != nil {
return fmt.Errorf("failed to describe function to get image details: %w", err)
}
function.Status.Deployment.Image = functionDescribe.Image

isMiddlewareUpdateEnabled, source, err := r.isMiddlewareUpdateEnabled(ctx, function)
if err != nil {
function.MarkMiddlewareNotUpToDate("MiddlewareCheckFailed", "Failed to check if middleware should be updated: %s", err)
return fmt.Errorf("failed to check if middleware should be updated: %w", err)
}
function.Status.Middleware.AutoUpdate.Enabled = isMiddlewareUpdateEnabled
function.Status.Middleware.AutoUpdate.Source = source
function.Status.Middleware.Current = functionDescribe.Middleware.Version
function.Status.Middleware.PendingRebuild = false

isOnLatestMiddleware, err := r.isMiddlewareLatest(ctx, metadata, function.Namespace)
if err != nil {
function.MarkMiddlewareNotUpToDate("MiddlewareCheckFailed", "Failed to check middleware version: %s", err.Error())
return fmt.Errorf("failed to check if function is using latest middleware: %w", err)
}

if !isOnLatestMiddleware {
isMiddlewareUpdateEnabled, source, err := r.isMiddlewareUpdateEnabled(ctx, function)
latestMiddleware, err := r.FuncCliManager.GetLatestMiddlewareVersion(ctx, metadata.Runtime, metadata.Invoke)
if err != nil {
function.MarkMiddlewareNotUpToDate("MiddlewareCheckFailed", "Failed to check if middleware should be updated: %s", err)
return fmt.Errorf("failed to check if middleware should be updated: %w", err)
return fmt.Errorf("failed to get latest available middleware version: %w", err)
}
function.Status.Middleware.Available = ptr.To(latestMiddleware)

if !isMiddlewareUpdateEnabled {
logger.Info("Skipping middleware update, as middleware update is disabled")
Expand All @@ -235,12 +251,7 @@ func (r *FunctionReconciler) handleMiddlewareUpdate(ctx context.Context, functio
logger.Info("Function is not on latest middleware and middleware update is enabled. Will redeploy")
function.MarkMiddlewareNotUpToDate("MiddlewareOutdated", "Middleware is outdated, redeploying")

// update function image in status before long redeploy operation
functionDescribe, err := r.FuncCliManager.Describe(ctx, metadata.Name, function.Namespace)
if err != nil {
return fmt.Errorf("failed to describe function to get image details: %w", err)
}
function.Status.Deployment.Image = functionDescribe.Image
function.Status.Middleware.PendingRebuild = true

// Flush status before long deploy operation
if err := FlushStatus(ctx, function); err != nil {
Expand All @@ -252,20 +263,26 @@ func (r *FunctionReconciler) handleMiddlewareUpdate(ctx context.Context, functio
return fmt.Errorf("failed to redeploy function: %w", err)
}

function.Status.Middleware.PendingRebuild = false
function.Status.Middleware.LastRebuild = metav1.Now()

// After successful deployment, middleware is now up-to-date
function.MarkMiddlewareUpToDate()
function.Status.Middleware.Available = nil // if function is on latest, we don't need to show this field
}
} else {
logger.Info("Function is deployed with latest middleware. No need to redeploy")
function.MarkMiddlewareUpToDate()
function.Status.Middleware.Available = nil // if function is on latest, we don't need to show this field
}

// Update deployment status
functionDescribe, err := r.FuncCliManager.Describe(ctx, metadata.Name, function.Namespace)
functionDescribe, err = r.FuncCliManager.Describe(ctx, metadata.Name, function.Namespace)
if err != nil {
return fmt.Errorf("failed to describe function to get image details: %w", err)
}
function.Status.Deployment.Image = functionDescribe.Image
function.Status.Middleware.Current = functionDescribe.Middleware.Version

function.MarkDeployReady()
return nil
Expand Down
27 changes: 27 additions & 0 deletions internal/controller/function_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,33 @@ var _ = Describe("Function Controller", func() {
"autoUpdateMiddleware": "true",
},
}),

Entry("Should populate the middleware information in the status", reconcileTestCase{
spec: functionsdevv1alpha1.FunctionSpec{
Repository: functionsdevv1alpha1.FunctionSpecRepository{
URL: "https://github.com/foo/bar",
},
AutoUpdateMiddleware: ptr.To(true),
},
configureMocks: func(funcMock *funccli.MockManager, gitMock *git.MockManager) {
funcMock.EXPECT().Describe(mock.Anything, functionName, resourceNamespace).Return(functions.Instance{
Middleware: functions.Middleware{
Version: "v2.0.0",
},
Image: "my-image:v1.2.3",
}, nil)
funcMock.EXPECT().GetLatestMiddlewareVersion(mock.Anything, mock.Anything, mock.Anything).Return("v2.0.0", nil)
funcMock.EXPECT().GetMiddlewareVersion(mock.Anything, functionName, resourceNamespace).Return("v2.0.0", nil)

gitMock.EXPECT().CloneRepository(mock.Anything, "https://github.com/foo/bar", "", "main", mock.Anything).Return(createTmpGitRepo(functions.Function{Name: "func-go"}), nil)
},
statusChecks: func(status *functionsdevv1alpha1.FunctionStatus) {
Expect(status.Middleware.Current).Should(Equal("v2.0.0"))
Expect(status.Middleware.AutoUpdate.Enabled).Should(BeTrue())
Expect(status.Middleware.AutoUpdate.Source).Should(Equal("function"))
Expect(status.Middleware.Available).Should(BeNil())
},
}),
)
})
})
Expand Down
Loading