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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep preview environment context in sync #11202

Merged
merged 3 commits into from
Jul 12, 2022
Merged

Keep preview environment context in sync #11202

merged 3 commits into from
Jul 12, 2022

Conversation

mads-hartmann
Copy link
Contributor

@mads-hartmann mads-hartmann commented Jul 7, 2022

Description

This PR implements the --watch option and uses it in .gitpod.yaml. I considered the following requirements:

  • It should deal with users changing branches
  • It should deal with users using "with-clean-slate-deployment"; that is, it should re-install the kubectx if the underlying VM is recreated.

Implementation

This changes the behaviour of "--watch" so that it runs forever and polls the current branch and VM periodically to see if a new preview environment context should be installed.

Alternative implementation

If we wanted to avoid polling could've created a channel for changes to the preview environment. For changes to the VM we could (I think) have used an Informer. Branch changes would be a bit more tricky though but might be achievable using a git hook that sends a signal to the process. Or if the current branch is stored in the filesystem we might be able to be notified on changes to that file.

I went with polling as that seemed like a smaller 馃浌

Related Issue(s)

Fixes #11108

How to test

# Run manually during development (or start a workspace off this branch as gitpod.yaml runs --watch
go run main.go install-context --watch

# To test switching branches:
# In another terminal
# change between a few different branches. See that it installs the context
git checkout main
# wait
kubectx
git checkout - 
# wait
kubectx

# To test re-creating the VM
werft run github -a with-clean-slate-deployment=true

Release Notes

NONE

Documentation

Werft options:

  • /werft with-preview
    N/A

@mads-hartmann mads-hartmann marked this pull request as ready for review July 8, 2022 10:19
@mads-hartmann mads-hartmann requested a review from a team July 8, 2022 10:19
Copy link
Contributor

@ArthurSens ArthurSens left a comment

Choose a reason for hiding this comment

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

Hey Mads, thanks for picking this up!

I like the decision of watching the VMI creation timestamp as the information we use to decide if a preview should be re-installed!

What I didn't understand was the need to implement the watch loops 馃.

@vulkoingim could probably elaborate more here, but my assumption is that when using informers (which we are), we're subscribing to specific events from kubernetes.

The events we're subscribed to are ADD and UPDATE from virtualmachines, but we decide to quit once we successfully install a context. Couldn't we just not quit, but keep watching for UPDATE instead?

dev/preview/previewctl/pkg/k8s/vm.go Show resolved Hide resolved
dev/preview/previewctl/pkg/preview/preview.go Show resolved Hide resolved
dev/preview/previewctl/pkg/preview/preview.go Outdated Show resolved Hide resolved
Co-authored-by: Arthur Silva Sens <arthursens2005@gmail.com>
@github-actions
Copy link
Contributor

鈿狅笍 Hey reviewer! BE CAREFUL 鈿狅笍
Review the code before opening in your Gitpod. .gitpod.yml was changed and it might be harmful.

@mads-hartmann
Copy link
Contributor Author

mads-hartmann commented Jul 11, 2022

What I didn't understand was the need to implement the watch loops

The "outer" watch loop serve two purposes

  1. Detecting if the VM has changed (e.g. was deleted and a new one created)
  2. Detecting if the branch has been changed

We could most likely fix (1) by changing preview.InstallContext so that it keeps listening for changes to the VM and proxy. But we can't add (2) without a larger refactoring. A "preview" (the struct) is currently associated with a single branch (which I think makes sense) so if we wanted to use that loop to install contexts for VMs from other branches it would get weird rather quickly.

The implementation in this branch has the following separation of concerns:

  1. preview.InstallContext is responsbile for installing a single context for a single VM. It implements a wait behaviour so it can be called even if the VM is not ready when you invoke it.
  2. The install context command implements a watch loop that monitors for changes to the current branch or VM and invokes preview.InstallContext if anything changed

We could improve it slightly by moving the "VM was changed" logic into "preview.InstallContext" so that the outer loop only looks for changes to the branch. I can do a quick time-boxed attempt at that and see if the result is nicer 鈽猴笍

Copy link
Contributor

@ArthurSens ArthurSens left a comment

Choose a reason for hiding this comment

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

As agreed in our team sync, let's get this merged since the PR solves the problem!

I just found a new problem here, but feel free to leave this to another PR if you prefer. We should be including any logic in the cmd package, all it is supposed to do is initialize commands and call functions 馃槵

Adding the /hold label so you can decide on tackling this now or in another PR

Comment on lines +22 to +43
// Used to ensure that we only install contexts
var lastSuccessfulPreviewEnvironment *preview.Preview = nil

install := func(timeout time.Duration) error {
p, err := preview.New("", logger)

if err != nil {
return err
}

if lastSuccessfulPreviewEnvironment != nil && lastSuccessfulPreviewEnvironment.Same(p) {
logger.Infof("The preview envrionment hasn't changed")
return nil
}

err = p.InstallContext(true, timeout)
if err == nil {
lastSuccessfulPreviewEnvironment = p
}
return err
}

Copy link
Contributor

Choose a reason for hiding this comment

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

This part looks a bit like an anti-pattern for the pattern we established 馃槵

To keep every logic testable, I believe we that code inside the cmd package should do nothing more than declare the CLI commands and calling functions from other packages.

If we move this part to a separate function the preview package, we can create tests for it 馃檪

Comment on lines +49 to +61
if watch {
for range time.Tick(15 * time.Second) {
// We're using a short timeout here to handle the scenario where someone switches
// to a branch that doens't have a preview envrionment. In that case the default
// timeout would mean that we would block for 10 minutes, potentially missing
// if the user changes to a new branch that does that a preview.
err := install(30 * time.Second)
if err != nil {
logger.WithFields(logrus.Fields{"err": err}).Info("Failed to install context. Trying again soon.")
}
}
} else {
return install(timeout)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above 馃槄

@ArthurSens
Copy link
Contributor

/hold

@mads-hartmann
Copy link
Contributor Author

mads-hartmann commented Jul 12, 2022

@ArthurSens Thanks! I'll merge this and follow-up on this in another PR

  1. Move logic away from cmd package
  2. See if it makes sense to only care about git in the "outer loop" and extend the inner-loop to deal with VMs being recreated

If I don't manage to get a PR open before I leave for the week I'll create an issue about this instead 鈽猴笍

@roboquat roboquat merged commit 8338b6b into main Jul 12, 2022
@roboquat roboquat deleted the mads/watch-forever branch July 12, 2022 12:45
@ArthurSens
Copy link
Contributor

ArthurSens commented Jul 12, 2022

If I don't manage to get a PR open before I leave for the week I'll create an issue about this instead 鈽猴笍

Sounds great!

  1. Move logic to cmd package

from* cmd 馃槢

@mads-hartmann
Copy link
Contributor Author

@ArthurSens haha, updated the comment to avoid confusion

@mads-hartmann
Copy link
Contributor Author

Follow-up issue created as I didn't get to it this week https://github.com/gitpod-io/ops/issues/3357

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Automatically add contexts for preview envs
3 participants