-
Notifications
You must be signed in to change notification settings - Fork 176
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
feat!: fully support project CRD #1388
Conversation
✅ Deploy Preview for docs-kargo-akuity-io ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #1388 +/- ##
==========================================
- Coverage 46.78% 46.45% -0.33%
==========================================
Files 136 140 +4
Lines 11897 12013 +116
==========================================
+ Hits 5566 5581 +15
- Misses 6129 6243 +114
+ Partials 202 189 -13 ☔ View full report in Codecov by Sentry. |
b72bb94
to
f4adf35
Compare
FreightLabelKey = "kargo.akuity.io/freight" | ||
ProjectLabelKey = "kargo.akuity.io/project" |
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.
Changed this symbol just for consistency with the others.
message Project { | ||
string name = 1; | ||
google.protobuf.Timestamp create_time = 2; | ||
} |
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.
This moved to types.proto
where we have the protobuf definitions of anything that's also a CRD.
apiGroups: ["kargo.akuity.io"] | ||
apiVersions: ["v1alpha1"] | ||
resources: ["projects"] | ||
operations: ["CREATE"] |
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.
For the moment, only need to validate creates.
if err = freight.SetupWebhookWithManager(mgr); err != nil { | ||
return errors.Wrap(err, "setup Freight webhook") | ||
} | ||
if err = project.SetupWebhookWithManager(mgr); err != nil { | ||
return errors.Wrap(err, "setup Project webhook") | ||
} | ||
if err = promotion.SetupWebhookWithManager(mgr); err != nil { | ||
return errors.Wrap(err, "setup Promotion webhook") | ||
} | ||
if err = promotionpolicy.SetupWebhookWithManager(mgr); err != nil { | ||
return errors.Wrap(err, "setup PromotionPolicy webhook") | ||
} | ||
if err = freight.SetupWebhookWithManager(mgr); err != nil { | ||
return errors.Wrap(err, "setup Freight webhook") | ||
if err = stage.SetupWebhookWithManager(mgr); err != nil { | ||
return errors.Wrap(err, "setup Stage webhook") | ||
} |
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.
Besides adding a webhook, I reordered these to be alphabetical.
return nil, nil, errors.Wrap(err, "new resmap from data") | ||
} | ||
cluster = make([]*unstructured.Unstructured, 0, resMap.Size()) | ||
for _, r := range resMap.ClusterScoped() { |
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.
To make this recognize Project as a cluster-scoped resource required jumping through a lot of hoops that were more easily avoided by refactoring this whole parser into the new splitYAML()
function that was adapted from GitOps Engine.
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
Signed-off-by: Kent Rancourt <[email protected]>
e16a4ea
to
83e8283
Compare
projects, otherResources, err := splitYAML(req.Msg.GetManifest()) | ||
if err != nil { | ||
return nil, connect.NewError(connect.CodeInvalidArgument, errors.Wrap(err, "parse manifest")) | ||
} | ||
|
||
size := len(cluster) + len(namespaced) | ||
res := make([]*svcv1alpha1.CreateResourceResult, 0, size) | ||
for _, obj := range cluster { | ||
res = append(res, s.createResource(ctx, obj)) | ||
} | ||
for _, obj := range namespaced { | ||
if err := s.validateProject(ctx, obj.GetNamespace()); err != nil { | ||
res = append(res, &svcv1alpha1.CreateResourceResult{ | ||
Result: &svcv1alpha1.CreateResourceResult_Error{ | ||
Error: err.Error(), | ||
}, | ||
}) | ||
continue | ||
} | ||
res = append(res, s.createResource(ctx, obj)) | ||
resources := append(projects, otherResources...) | ||
res := make([]*svcv1alpha1.CreateResourceResult, 0, len(resources)) | ||
for _, r := range resources { | ||
resource := r // Avoid implicit memory aliasing | ||
res = append(res, s.createResource(ctx, &resource)) |
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.
Now that the Namespace
creation is async (it requires a reconciliation by the management controller before the underlying namespace actually gets created), have you noticed if we encounter timing-related failures because of that slight delay introduced by Project -> Namespace creation? (e.g. the Namespace didn't get created in time before the Stage).
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.
It is possible, but so far I've seen it only once out of probably 50+ times I have done this.
I'd been contemplating how to make that more foolproof. I could probably add logic here to wait for project readiness before moving on to non-project resources.
I'm going to open a follow-up issue.
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.
Right here so we don't lose track:
// Validate that a namespace matching the project name doesn't already exist. | ||
namespace := &corev1.Namespace{} | ||
if err := w.getNamespaceFn( | ||
ctx, | ||
client.ObjectKey{Name: project.Name}, | ||
namespace, | ||
); err != nil { | ||
if client.IgnoreNotFound(err) == nil { | ||
// This is good. The namespace doesn't already exist. | ||
return nil, nil | ||
} | ||
return nil, apierrors.NewInternalError( | ||
errors.Wrapf(err, "error getting namespace %q", project.Name), | ||
) | ||
} |
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.
Since you also have logic in the Project controller to fail project initialization if the namespace already exists, does the webhook serve to provide immediate feedback instead of delayed feedback of a pre-existing namespace?
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.
Yes. That's it exactly. Fail synchronously if we can spot the problem sooner.
Fixes #558
Fixes #667
Summary
This PR relieves the API server of responsibility (and permissions) for creating specially labeled namespaces that we count as "projects."
Project creation via API server now entails creation of a Project resource. The controller reconciles new Project resources by creating the corresponding namespace. Project resources are set as the owner of the associated namespace, so Project deletion takes the associated namespace with it. The reverse is also true. Namespaces have a finalizer that, upon deletion, is only cleared by the controller deleting the associated Project resource.
Follow-up PRs will add to this to create things like ServiceAccounts, Roles, and RoleBindings in the project namespaces.
Breakdown
About 2/3 of this is generated code, so please don't be intimidated by the size.
Narrowly scoped commits cover each of the following:
go mod tidy
: Refactor of API server "apply" endpoints removed a dependencyWhat doesn't change
Anywhere in the code where we validate the existence of a Project, we still do so by validating the existence of the corresponding namespace, since that's usually what we actually care about.
This PR does not address #1389. That will be addressed in a follow-up.