Add gitops controller - #36
Conversation
PR Summary by QodoAdd GitOps controller and GitRepository API
AI Description
Diagram
High-Level Assessment
Files changed (35)
|
Code Review by Qodo
1.
|
| slog.WarnContext(ctx, "Parse error", "id", repo.ID, "file", pe.File, "error", pe.Err) | ||
| } | ||
|
|
||
| // Abort reconciliation if all files failed to parse — this prevents |
There was a problem hiding this comment.
why all and just not 1? What if a previously well formatted file is now corrupted?
There was a problem hiding this comment.
Agree and the same risk exists when only some files fail: desired map omits them, so they look “removed from Git” and get deleted.
the enhancement conflict table says "invalid YAML -> skip file / report error" not delete.
Why treat a parse failure as absence?
There was a problem hiding this comment.
It would bring complexity. We would need to start storing which file produced which instance. Is it ok for first iteration to have at least this error, which basically only detect, permissions/disk issues for example.
There was a problem hiding this comment.
ok for v1 but this must be tracked
| slog.WarnContext(ctx, "Parse error", "id", repo.ID, "file", pe.File, "error", pe.Err) | ||
| } | ||
|
|
||
| // Abort reconciliation if all files failed to parse — this prevents |
There was a problem hiding this comment.
Agree and the same risk exists when only some files fail: desired map omits them, so they look “removed from Git” and get deleted.
the enhancement conflict table says "invalid YAML -> skip file / report error" not delete.
Why treat a parse failure as absence?
| return nil | ||
| } | ||
|
|
||
| func (r *Reconciler) createInstance(ctx context.Context, _, _ string, desired DesiredInstance) error { |
There was a problem hiding this comment.
Why take repoID / commit and discard them as _?
Enhancement says set gitops.dcm.io/repository and gitops.dcm.io/commit on create. Is that deferred to a follow up PR? or should the enhancement be updated?
There was a problem hiding this comment.
Right, added it so labels are set in CatalogIntance.
| var reconcileErrors []string | ||
| for _, desired := range toCreate { | ||
| slog.InfoContext(ctx, "Creating instance from Git", "id", repo.ID, "instance_name", desired.Name) | ||
| if err := r.createInstance(ctx, repo.ID, latestCommit, desired); err != nil { |
There was a problem hiding this comment.
On create/delete failure we append to reconcileErrors and later set ERROR. repo.MaxRetries and repo.BackoffSeconds are never used. why ignore them here?
There was a problem hiding this comment.
Right, AI missed it, I'll remove for now for, easier review.
There was a problem hiding this comment.
spec.reconciliation.retry_policy is still in OpenAPI and still not stored or applied.
| '500': | ||
| $ref: '#/components/responses/InternalServerError' | ||
|
|
||
| /git-repositories/{gitRepositoryId}: |
There was a problem hiding this comment.
Enhancement still lists GET …/status and POST …:sync.
The drop seems intentional so we need to update the enhancement, no?
There was a problem hiding this comment.
Yes and no. Those features can be implemented as follow-ups, if there is a reason to have them, or update enhacenemt. Let's see, but I think it would be better to have it as simple as possible, as DCM still lacks to many things, so it doesn't make sense to make gitops complicated for time being.
| pollInterval := time.Duration(cfg.PollInterval) * time.Second | ||
| ctrl := controller.NewController(reconciler, gitopsDataStore, pollInterval) | ||
|
|
||
| ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) |
There was a problem hiding this comment.
Not previously flagged: everything downstream of this context — including the catalogSvc.Create/Delete calls the reconciler makes — runs with no caller identity attached. Combined with the unscoped listing above, there's no notion anywhere in this path of which repository (or which user) is allowed to touch which instance.
There was a problem hiding this comment.
Not sure I understand, there is no authz implemented rn, what do you mean? Also this reconciler never creates/removes catalog ussing catalogSvc.
There was a problem hiding this comment.
It does — r.catalogSvc is catalogservice.CatalogItemInstanceService (injected via catalogSvc.CatalogItemInstance() in run.go), and the reconciler calls Delete at line 129 and Create at line 173.
Re: authz — not claiming that's new, just that there's no identity plumbing for it to ever attach to here. Combined with the unscoped listManagedInstances above, this path has no way to even express "which repo owns which instance," so it's not just pending auth/z, there's nothing yet to enforce against.
25c34c5 to
46a586f
Compare
bf94d55 to
6906411
Compare
Define the GitRepository API with endpoints for CRUD, sync status, and immediate sync trigger. Set up oapi-codegen configs and Makefile targets to generate types, server, and client code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Implement the data persistence layer for GitRepository resources including CRUD operations, sync status updates, pagination, and unique constraint handling. Includes unit tests with SQLite. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Implement the business logic and HTTP handler layers for the GitRepository API. The service handles validation and API-to-model conversion; handlers implement the generated StrictServerInterface. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Register GitRepository model in AutoMigrate, mount routes on the chi router, add OpenAPI request validation, and create build-gitops Makefile target. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Implement the reconciliation engine that polls Git repositories and syncs CatalogItemInstance lifecycle state. Includes YAML parser for non-recursive file discovery, git clone/fetch via CLI, reconciler that classifies create/delete operations, and a controller loop with per-repo interval tracking. Includes parser unit tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Add the separate dcm-gitops process entry point that runs the GitOps controller. Wires up database, catalog service stack, and controller. Includes Containerfile with git-core installed for clone/fetch ops. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Status is already returned as part of GET /git-repositories/{gitRepositoryId},
making the dedicated status endpoint unnecessary.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Ondra Machacek <omachace@redhat.com>
- Add db.AutoMigrate for GitRepository in dcm-gitops startup - Remove unimplemented sync endpoint (POST :sync) from API, handlers, service, and generated server/client code - Validate repoID format in GitClient to prevent directory traversal - Add nil check on inst.Uid to prevent panic in reconciler - Abort reconciliation when all YAML files fail to parse, preventing mass-deletion of existing instances - Add 2-minute context timeout for git clone/fetch operations - Add per-repo mutex in controller to prevent concurrent reconciliations - Add input validation in service layer: display_name, URL format, interval_seconds bounds, retry policy bounds Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Switch GitClient from shelling out to the git binary to using go-git, a pure Go git implementation. This eliminates the runtime dependency on the git CLI and allows removing git-core from the container image. The GitOperations interface is unchanged so all callers (reconciler, tests) continue to work without modification. Also adds a LatestRemoteCommit helper for lightweight remote polling without a full clone. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Remove unused LatestRemoteCommit function, drop unused branch param from cloneRepo and unused refName param from fetchAndReset, and fix import ordering. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Apply gofumpt formatting, add missing package comments, remove unused label constants and rename unused parameters to _. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
- Add managed_instance table to track repo->instance ownership, preventing the reconciler from deleting instances it does not own - Inject gitops and user-defined labels on all catalog item resources, not just those referenced in user_values - Restrict git repository URLs to https/http/ssh schemes and block localhost, link-local, and cloud metadata endpoints - Preserve last_synced_commit on error instead of clearing it Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Ondra Machacek <omachace@redhat.com>
Signed-off-by: Ondra Machacek <omachace@redhat.com>
Implements: https://github.com/dcm-project/enhancements/blob/main/enhancements/gitops-controller/gitops-controller.md