-
Notifications
You must be signed in to change notification settings - Fork 56
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
Fix stack state message regression #107
Merged
+137
−70
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
cdbd0f2
WIP fixes for #102
50459f6
Update CRD and avoid clobbering last successful commit
f5d54b9
Record actual git commit instead of using spec value
9dd97fe
Delete working directory after reconciliation - should help with #104
89aead3
Address PR comments
fc5739e
Improve tests
3103e59
Adding more tests to cover lifecycle of stack with success and failure
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,6 @@ import ( | |
"github.com/pulumi/pulumi/sdk/v2/go/x/auto/optup" | ||
giturls "github.com/whilp/git-urls" | ||
git "gopkg.in/src-d/go-git.v4" | ||
"gopkg.in/src-d/go-git.v4/plumbing" | ||
corev1 "k8s.io/api/core/v1" | ||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | ||
k8serrors "k8s.io/apimachinery/pkg/api/errors" | ||
|
@@ -174,6 +173,14 @@ func (r *ReconcileStack) Reconcile(request reconcile.Request) (reconcile.Result, | |
return reconcile.Result{}, err | ||
} | ||
|
||
currentCommit, err := revisionAtWorkingDir(sess.workdir) | ||
if err != nil { | ||
return reconcile.Result{}, err | ||
} | ||
|
||
// Delete the working directory after the reconciliation is completed (regardless of success or failure). | ||
defer sess.CleanupPulumiWorkdir() | ||
|
||
// Step 2. If there are extra environment variables, read them in now and use them for subsequent commands. | ||
err = sess.SetEnvs(stack.Envs, request.Namespace) | ||
if err != nil { | ||
|
@@ -206,24 +213,12 @@ func (r *ReconcileStack) Reconcile(request reconcile.Request) (reconcile.Result, | |
} | ||
time.Sleep(2 * time.Second) // arbitrary sleep after finalizer add to avoid stale obj for permalink | ||
// Add default permalink for the stack in the Pulumi Service. | ||
sess.addDefaultPermalink(instance) | ||
if err := sess.addDefaultPermalink(instance); err != nil { | ||
return reconcile.Result{}, err | ||
} | ||
} | ||
} | ||
|
||
// Run the Pulumi update iff the desired state has not already been | ||
// reached, or if it is marked to be deleted. | ||
err = sess.getLatestResource(instance, request.NamespacedName) | ||
if err != nil { | ||
sess.logger.Error(err, "Failed to get latest Stack before updating Stack", "Stack.Name", instance.Spec.Stack) | ||
return reconcile.Result{}, err | ||
} | ||
isStackMarkedToBeDeleted = instance.GetDeletionTimestamp() != nil | ||
// Don't run rest of loop if already at desired state, unless marked for deletion. | ||
if !isStackMarkedToBeDeleted && (instance.Status.LastUpdate != nil && instance.Status.LastUpdate.State == instance.Spec.Commit) { | ||
reqLogger.Info("Stack already at desired state", "Stack.Commit", instance.Spec.Commit) | ||
return reconcile.Result{}, nil | ||
} | ||
|
||
// Step 3. If a stack refresh is requested, run it now. | ||
if sess.stack.Refresh { | ||
permalink, err := sess.RefreshStack(sess.stack.ExpectNoRefreshChanges) | ||
|
@@ -237,12 +232,10 @@ func (r *ReconcileStack) Reconcile(request reconcile.Request) (reconcile.Result, | |
return reconcile.Result{}, err | ||
} | ||
if instance.Status.LastUpdate == nil { | ||
instance.Status.LastUpdate = &pulumiv1alpha1.StackUpdateState{ | ||
Permalink: permalink, | ||
} | ||
} else { | ||
instance.Status.LastUpdate.Permalink = permalink | ||
instance.Status.LastUpdate = &pulumiv1alpha1.StackUpdateState{} | ||
} | ||
instance.Status.LastUpdate.Permalink = permalink | ||
|
||
err = sess.updateResourceStatus(instance) | ||
if err != nil { | ||
reqLogger.Error(err, "Failed to update Stack status for refresh", "Stack.Name", stack.Stack) | ||
|
@@ -269,10 +262,10 @@ func (r *ReconcileStack) Reconcile(request reconcile.Request) (reconcile.Result, | |
if err != nil { | ||
reqLogger.Error(err, "Failed to update Stack", "Stack.Name", stack.Stack) | ||
// Update Stack status with failed state | ||
instance.Status.LastUpdate = &pulumiv1alpha1.StackUpdateState{ | ||
State: pulumiv1alpha1.FailedStackStateMessage, | ||
Permalink: permalink, | ||
} | ||
instance.Status.LastUpdate.LastAttemptedCommit = currentCommit | ||
instance.Status.LastUpdate.State = pulumiv1alpha1.FailedStackStateMessage | ||
instance.Status.LastUpdate.Permalink = permalink | ||
|
||
if err2 := sess.updateResourceStatus(instance); err2 != nil { | ||
msg := "Failed to update status for a failed Stack update" | ||
err3 := errors.Wrapf(err, err2.Error()) | ||
|
@@ -299,14 +292,11 @@ func (r *ReconcileStack) Reconcile(request reconcile.Request) (reconcile.Result, | |
return reconcile.Result{}, err | ||
} | ||
instance.Status.Outputs = outs | ||
if instance.Status.LastUpdate == nil { | ||
instance.Status.LastUpdate = &pulumiv1alpha1.StackUpdateState{ | ||
State: instance.Spec.Commit, | ||
Permalink: permalink, | ||
} | ||
} else { | ||
instance.Status.LastUpdate.State = instance.Spec.Commit | ||
instance.Status.LastUpdate.Permalink = permalink | ||
instance.Status.LastUpdate = &pulumiv1alpha1.StackUpdateState{ | ||
State: pulumiv1alpha1.SucceededStackStateMessage, | ||
LastAttemptedCommit: currentCommit, | ||
LastSuccessfulCommit: currentCommit, | ||
Permalink: permalink, | ||
} | ||
err = sess.updateResourceStatus(instance) | ||
if err != nil { | ||
|
@@ -377,12 +367,12 @@ func (sess *reconcileStackSession) addFinalizer(stack *pulumiv1alpha1.Stack) err | |
} | ||
|
||
type reconcileStackSession struct { | ||
logger logr.Logger | ||
kubeClient client.Client | ||
accessToken string | ||
stack pulumiv1alpha1.StackSpec | ||
autoStack *auto.Stack | ||
workdir string | ||
logger logr.Logger | ||
kubeClient client.Client | ||
accessToken string | ||
stack pulumiv1alpha1.StackSpec | ||
autoStack *auto.Stack | ||
workdir string | ||
} | ||
|
||
// blank assignment to verify that reconcileStackSession implements pulumiv1alpha1.StackController. | ||
|
@@ -399,25 +389,6 @@ func newReconcileStackSession( | |
} | ||
} | ||
|
||
// gitCloneAndCheckoutCommit clones the Git repository and checkouts the specified commit hash or branch. | ||
func gitCloneAndCheckoutCommit(url, hash, branch, path string) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this handled elsewhere now? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes - its done by the automation api so this was unused. See |
||
repo, err := git.PlainClone(path, false, &git.CloneOptions{URL: url}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
w, err := repo.Worktree() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return w.Checkout(&git.CheckoutOptions{ | ||
Hash: plumbing.NewHash(hash), | ||
Branch: plumbing.ReferenceName(branch), | ||
Force: true, | ||
}) | ||
} | ||
|
||
// SetEnvs populates the environment the stack run with values | ||
// from an array of Kubernetes ConfigMaps in a Namespace. | ||
func (sess *reconcileStackSession) SetEnvs(configMapNames []string, namespace string) error { | ||
|
@@ -531,6 +502,7 @@ func (sess *reconcileStackSession) SetupPulumiWorkdir(gitAuth *auto.GitAuth) err | |
if sess.accessToken != "" { | ||
w.SetEnvVar("PULUMI_ACCESS_TOKEN", sess.accessToken) | ||
} | ||
sess.workdir = w.WorkDir() | ||
|
||
// Create a new stack if the stack does not already exist, or fall back to | ||
// selecting the existing stack. If the stack does not exist, it will be created and selected. | ||
|
@@ -555,6 +527,27 @@ func (sess *reconcileStackSession) SetupPulumiWorkdir(gitAuth *auto.GitAuth) err | |
return nil | ||
} | ||
|
||
func (sess *reconcileStackSession) CleanupPulumiWorkdir() { | ||
if sess.workdir != "" { | ||
if err := os.RemoveAll(sess.workdir); err != nil { | ||
sess.logger.Error(err, "Failed to delete working dir: %s", sess.workdir) | ||
} | ||
} | ||
} | ||
|
||
// Determine the actual commit information from the working directory (Spec commit etc. is optional). | ||
func revisionAtWorkingDir(workingDir string) (string, error) { | ||
gitRepo, err := git.PlainOpen(workingDir) | ||
if err != nil { | ||
return "", errors.Wrapf(err, "failed to resolve git repository from working directory: %s", workingDir) | ||
} | ||
headRef, err := gitRepo.Head() | ||
if err != nil { | ||
return "", errors.Wrapf(err, "failed to determine revision for git repository at %s", workingDir) | ||
} | ||
return headRef.Hash().String(), nil | ||
} | ||
|
||
func (sess *reconcileStackSession) InstallProjectDependencies(ctx context.Context, workspace auto.Workspace) error { | ||
project, err := workspace.ProjectSettings(ctx) | ||
if err != nil { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was the original argument for short-circuiting here? I believe it's correct to not do this, but not sure exactly why it was added and thus not sure what potentially undesirable consequence this might have?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not really sure on this unfortunately. One theory I have is that this was an attempt at avoiding reconciliation loops (modifying the stack CR in the reconciliation loop causes more reconciliations to trigger). #29 introduced this change and was also intended to address the reconciliation loop issue. I am running the integration tests which apparently reproduced the issues so I am hoping we can build confidence with them before pushing this change.