-
Notifications
You must be signed in to change notification settings - Fork 54
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
[DEVHAS-488]annotation to force generate gitops #410
Merged
yangcao77
merged 10 commits into
redhat-appstudio:main
from
yangcao77:488-annotation-to-generate-gitops
Nov 15, 2023
Merged
Changes from 3 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
d82ae25
add force annotation check
yangcao77 a0f0a28
rebase
yangcao77 d7350e8
set annotation back to false once generation successfully completed
yangcao77 5a02383
rebase
yangcao77 a94bbac
address review comments
yangcao77 bb4bb62
update message and time
yangcao77 047dd4c
add test
yangcao77 83d06a4
rebase
yangcao77 c6c10f4
clean up
yangcao77 c2ab406
rebase
yangcao77 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
"os" | ||
"path/filepath" | ||
"reflect" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
|
@@ -78,6 +79,7 @@ | |
applicationFailCounterAnnotation = "applicationFailCounter" | ||
maxApplicationFailCount = 5 | ||
componentName = "Component" | ||
forceGenerationAnnotation = "forceGitopsGeneration" | ||
) | ||
|
||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=components,verbs=get;list;watch;create;update;patch;delete | ||
|
@@ -131,6 +133,13 @@ | |
} | ||
|
||
setCounterAnnotation(applicationFailCounterAnnotation, &component, 0) | ||
forceGenerateGitopsResource := false | ||
forceGenerateGitopsResource, err = getForceGenerateGitopsAnnotation(component) | ||
if err != nil { | ||
log.Info("failed to get forceGeneration annotation, set forceGenerateGitopsResource to false") | ||
forceGenerateGitopsResource = false | ||
} | ||
log.Info(fmt.Sprintf("forceGenerateGitopsResource is %v", forceGenerateGitopsResource)) | ||
|
||
ghClient, err := r.GitHubTokenClient.GetNewGitHubClient("") | ||
if err != nil { | ||
|
@@ -180,7 +189,7 @@ | |
log.Info(fmt.Sprintf("added the finalizer %v", req.NamespacedName)) | ||
} | ||
} else { | ||
if hasApplication.Status.Devfile != "" && len(component.Status.Conditions) > 0 && component.Status.Conditions[len(component.Status.Conditions)-1].Status == metav1.ConditionTrue && containsString(component.GetFinalizers(), compFinalizerName) { | ||
if hasApplication.Status.Devfile != "" && (forceGenerateGitopsResource || len(component.Status.Conditions) > 0 && component.Status.Conditions[len(component.Status.Conditions)-1].Status == metav1.ConditionTrue && containsString(component.GetFinalizers(), compFinalizerName)) { | ||
// only attempt to finalize and update the gitops repo if an Application is present & the previous Component status is good | ||
// A finalizer is present for the Component CR, so make sure we do the necessary cleanup steps | ||
metrics.ComponentDeletionTotalReqs.Inc() | ||
|
@@ -217,7 +226,7 @@ | |
isUpdateConditionPresent := false | ||
isGitOpsRegenSuccessful := false | ||
for _, condition := range component.Status.Conditions { | ||
if condition.Type == "GitOpsResourcesGenerated" && condition.Reason == "GenerateError" && condition.Status == metav1.ConditionFalse { | ||
if forceGenerateGitopsResource || (condition.Type == "GitOpsResourcesGenerated" && condition.Reason == "GenerateError" && condition.Status == metav1.ConditionFalse) { | ||
log.Info(fmt.Sprintf("Re-attempting GitOps generation for %s", component.Name)) | ||
// Parse the Component Devfile | ||
compDevfileData, err := cdqanalysis.ParseDevfileWithParserArgs(&devfileParser.ParserArgs{Data: []byte(component.Status.Devfile), Token: gitToken}) | ||
|
@@ -234,6 +243,7 @@ | |
return ctrl.Result{}, err | ||
} else { | ||
log.Info(fmt.Sprintf("GitOps re-generation successful for %s", component.Name)) | ||
setForceGenerateGitopsAnnotation(&component, "false") | ||
err := r.SetGitOpsGeneratedConditionAndUpdateCR(ctx, req, &component, nil) | ||
if err != nil { | ||
return ctrl.Result{}, err | ||
|
@@ -308,8 +318,8 @@ | |
if gitToken == "" { | ||
gitURL, err = cdqanalysis.ConvertGitHubURL(source.GitSource.URL, source.GitSource.Revision, context) | ||
if err != nil { | ||
// ConvertGitHubURL only returns user error | ||
metrics.ImportGitRepoSucceeded.Inc() | ||
log.Error(err, fmt.Sprintf("Unable to convert Github URL to raw format, exiting reconcile loop %v", req.NamespacedName)) | ||
_ = r.SetCreateConditionAndUpdateCR(ctx, req, &component, err) | ||
return ctrl.Result{}, err | ||
|
@@ -331,21 +341,21 @@ | |
// Use SPI to retrieve the devfile from the private repository | ||
devfileBytes, devfileLocation, err = spi.DownloadDevfileUsingSPI(r.SPIClient, ctx, component, gitURL, source.GitSource.Revision, context) | ||
if err != nil { | ||
// Increment the import git repo failed metric on non-user errors | ||
if _, ok := err.(*devfile.NoFileFound); !ok { | ||
metrics.ImportGitRepoFailed.Inc() | ||
} else { | ||
metrics.ImportGitRepoSucceeded.Inc() | ||
} | ||
log.Error(err, fmt.Sprintf("Unable to download from any known devfile locations from %s %v", gitURL, req.NamespacedName)) | ||
_ = r.SetCreateConditionAndUpdateCR(ctx, req, &component, err) | ||
return ctrl.Result{}, err | ||
} | ||
metrics.ImportGitRepoSucceeded.Inc() | ||
|
||
gitURL, err := cdqanalysis.ConvertGitHubURL(source.GitSource.URL, source.GitSource.Revision, context) | ||
if err != nil { | ||
log.Error(err, fmt.Sprintf("Unable to convert Github URL to raw format, exiting reconcile loop %v", req.NamespacedName)) | ||
_ = r.SetCreateConditionAndUpdateCR(ctx, req, &component, err) | ||
return ctrl.Result{}, err | ||
} | ||
|
@@ -610,16 +620,16 @@ | |
if err != nil { | ||
retErr := err | ||
if strings.Contains(strings.ToLower(err.Error()), "github push protection") { | ||
retErr = fmt.Errorf("potential secret leak caught by github push protection") | ||
// to get the URL token | ||
// e.g. <GitURL>/security/secret-scanning/unblock-secret/2WlUv72plUf05tgshlpRLzSlH4R \n | ||
var unblockURL string | ||
splited := strings.Split(strings.ToLower(err.Error()), "unblock-secret/") | ||
if len(splited) > 1 { | ||
token := strings.Split(splited[1], " ")[0] | ||
unblockURL = fmt.Sprintf("%v/security/secret-scanning/unblock-secret/%v", component.Status.GitOps.RepositoryURL, token) | ||
log.Error(retErr, fmt.Sprintf("unable to generate gitops resources due to git push protecton error, follow the link to unblock the secret: %v", unblockURL)) | ||
} | ||
} else { | ||
log.Error(retErr, "unable to generate gitops resources due to error") | ||
} | ||
|
@@ -631,23 +641,23 @@ | |
metrics.ControllerGitRequest.With(prometheus.Labels{"controller": componentName, "tokenName": ghClient.TokenName, "operation": "CommitAndPush"}).Inc() | ||
err = r.Generator.CommitAndPush(tempDir, "", gitOpsURL, mappedGitOpsComponent.Name, gitOpsBranch, "Generating GitOps resources") | ||
if err != nil { | ||
retErr := err | ||
if strings.Contains(strings.ToLower(err.Error()), "github push protection") { | ||
retErr = fmt.Errorf("potential secret leak caught by github push protection") | ||
// to get the URL token | ||
// e.g. <GitURL>/security/secret-scanning/unblock-secret/2WlUv72plUf05tgshlpRLzSlH4R \n | ||
var unblockURL string | ||
splited := strings.Split(strings.ToLower(err.Error()), "unblock-secret/") | ||
if len(splited) > 1 { | ||
token := strings.Split(splited[1], " ")[0] | ||
unblockURL = fmt.Sprintf("%v/security/secret-scanning/unblock-secret/%v", component.Status.GitOps.RepositoryURL, token) | ||
log.Error(retErr, fmt.Sprintf("unable to commit and push gitops resources due to git push protecton error, follow the link to unblock the secret: %v", unblockURL)) | ||
} | ||
} else { | ||
log.Error(retErr, "unable to commit and push gitops resources due to error") | ||
} | ||
ioutils.RemoveFolderAndLogError(log, r.AppFS, tempDir) | ||
return retErr | ||
} | ||
|
||
// Get the commit ID for the gitops repository | ||
|
@@ -754,3 +764,21 @@ | |
return ctrl.Result{}, componentErr | ||
} | ||
} | ||
|
||
// getForceGenerateGitopsAnnotation gets the internal annotation on the component whether to force generate the gitops resource | ||
func getForceGenerateGitopsAnnotation(component appstudiov1alpha1.Component) (bool, 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. We can simplify this a fair bit by avoiding casting the string to bool (which means we also don't need to return an err)
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. updated |
||
compAnnotations := component.GetAnnotations() | ||
if compAnnotations == nil || compAnnotations[forceGenerationAnnotation] == "" { | ||
return false, nil | ||
} else { | ||
return strconv.ParseBool(compAnnotations[forceGenerationAnnotation]) | ||
} | ||
} | ||
|
||
func setForceGenerateGitopsAnnotation(component *appstudiov1alpha1.Component, value string) { | ||
compAnnotations := component.GetAnnotations() | ||
if compAnnotations == nil { | ||
compAnnotations = make(map[string]string) | ||
} | ||
compAnnotations[forceGenerationAnnotation] = value | ||
} |
Oops, something went wrong.
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.
The person or the tool that sets the annotations can handle un setting the annotation. I don't think we need a dedicated function for setting it to false.
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'm thinking the person or HAC can enable the force generation, but they are not going to track it? and after the regeneration is done, should this be set to
false
? or the expected usage will be after enabling, the gitops resource going to attempt regeneration in every following reconcile?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 think the expected usage should be that as long as the annotation is present, every reconcile will re-generate the gitops resources. It's up to the user or tool to remove it.
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.
have discussed in team meeting, setting the annotation to false when a force generation is done