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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: sync repository content with datastore #467

Merged
merged 16 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions api/v1alpha1/terraformrepository_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,35 @@ type TerraformRepositoryRepository struct {

// TerraformRepositoryStatus defines the observed state of TerraformRepository
type TerraformRepositoryStatus struct {
State string `json:"state,omitempty"`
Branches []BranchState `json:"branches,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
}

// BranchState describes the sync state of a branch
type BranchState struct {
Name string `json:"name,omitempty"`
LatestRev string `json:"latestRev,omitempty"`
LastSyncDate string `json:"lastSyncDate,omitempty"`
LastSyncStatus string `json:"lastSyncStatus,omitempty"`
}

// GetBranchState searches for a branch with the specified name in the given slice of BranchState.
// It returns a pointer to the BranchState if found, along with a boolean indicating success.
// If the branch is not found, it returns nil and false.
func GetBranchState(name string, branches []BranchState) (*BranchState, bool) {
for _, branch := range branches {
if branch.Name == name {
return &branch, true
}
}
return nil, false
}

// +kubebuilder:object:root=true
// +kubebuilder:resource:shortName=repositories;repository;repo;tfrs;tfr;
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="State",type=string,JSONPath=`.status.state`
// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.repository.url`
// TerraformRepository is the Schema for the terraformrepositories API
type TerraformRepository struct {
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion cmd/controllers/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ func buildControllersStartCmd(app *burrito.App) *cobra.Command {
defaultOnErrorTimer, _ := time.ParseDuration("10s")
defaultWaitActionTimer, _ := time.ParseDuration("5s")
defaultFailureGracePeriod, _ := time.ParseDuration("15s")
defaultRepositorySyncTimer, _ := time.ParseDuration("5m")

cmd.Flags().StringSliceVar(&app.Config.Controller.Namespaces, "namespaces", []string{"burrito-system"}, "list of namespaces to watch")
cmd.Flags().StringSliceVar(&app.Config.Controller.Types, "types", []string{"layer", "repository", "run", "pullrequest"}, "list of controllers to start")
cmd.Flags().StringArrayVar(&app.Config.Controller.Types, "types", []string{"layer", "run", "pullrequest"}, "list of controllers to start")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.DriftDetection, "drift-detection-period", defaultDriftDetectionTimer, "period between two plans. Must end with s, m or h.")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.RepositorySync, "repository-sync-period", defaultRepositorySyncTimer, "period between two repository sync. Must end with s, m or h.")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.OnError, "on-error-period", defaultOnErrorTimer, "period between two runners launch when an error occurred in the controllers. Must end with s, m or h.")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.WaitAction, "wait-action-period", defaultWaitActionTimer, "period between two runners when a layer is locked. Must end with s, m or h.")
cmd.Flags().DurationVar(&app.Config.Controller.Timers.FailureGracePeriod, "failure-grace-period", defaultFailureGracePeriod, "initial time before retry, goes exponential function of number failure. Must end with s, m or h.")
Expand Down
7 changes: 7 additions & 0 deletions deploy/charts/burrito/templates/controllers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ spec:
- name: burrito-config
mountPath: /etc/burrito
readOnly: true
- name: ssh-known-hosts
mountPath: /home/burrito/.ssh/known_hosts
subPath: known_hosts
readOnly: true
- name: burrito-token
mountPath: /var/run/secrets/token
readOnly: true
Expand Down Expand Up @@ -88,6 +92,9 @@ spec:
- name: burrito-config
configMap:
name: burrito-config
- name: ssh-known-hosts
configMap:
name: burrito-ssh-known-hosts
- name: burrito-token
projected:
sources:
Expand Down
13 changes: 9 additions & 4 deletions deploy/charts/burrito/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ config:
timers:
# -- Drift detection interval
driftDetection: 10m
# -- Repository polling interval
repositorySync: 5m
# -- Duration to wait before retrying on error
onError: 10s
# -- Duration to wait before retrying on locked layer
Expand All @@ -28,8 +30,9 @@ config:
maxConcurrentReconciles: 1
# -- Maximum number of retries for Terraform operations (plan, apply...)
terraformMaxRetries: 3
# -- Resource types to watch for reconciliation
types: ["layer", "repository", "run", "pullrequest"]
# TODO: enable repository controller by default
# -- Resource types to watch for reconciliation. Note: by default repository controller is disabled as it is not yet fully usable.
types: ["layer", "run", "pullrequest"]
leaderElection:
# -- Enable/Disable leader election
enabled: true
Expand Down Expand Up @@ -271,7 +274,9 @@ controllers:
# -- Environment variables to pass to the Burrito controller container
envFrom: []
# -- Environment variables to pass to the Burrito controller container
env: []
env:
- name: SSH_KNOWN_HOSTS
value: /home/burrito/.ssh/known_hosts
# -- Additional volumes
extraVolumes: {}
# -- Additional volume mounts
Expand Down Expand Up @@ -314,7 +319,7 @@ server:
initialDelaySeconds: 5
periodSeconds: 20
# -- Environment variables to pass to the Burrito server container
env: []
env: []
# -- Environment variables to pass to the Burrito server container
envFrom: []
# -- Additional volumes
Expand Down
6 changes: 6 additions & 0 deletions internal/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package annotations

import (
"context"
"strings"

"sigs.k8s.io/controller-runtime/pkg/client"
)
Expand All @@ -21,13 +22,18 @@ const (
LastBranchCommitDate string = "webhook.terraform.padok.cloud/branch-commit-date"
LastRelevantCommit string = "webhook.terraform.padok.cloud/relevant-commit"
LastRelevantCommitDate string = "webhook.terraform.padok.cloud/relevant-commit-date"
SyncBranchNow string = "webhook.terraform.padok.cloud/sync-"

ForceApply string = "notifications.terraform.padok.cloud/force-apply"
AdditionnalTriggerPaths string = "config.terraform.padok.cloud/additionnal-trigger-paths"

SyncNow string = "api.terraform.padok.cloud/sync-now"
)

func ComputeKeyForSyncBranchNow(branch string) string {
return SyncBranchNow + strings.ReplaceAll(branch, "/", "--")
}

func Add(ctx context.Context, c client.Client, obj client.Object, annotations map[string]string) error {
newObj := obj.DeepCopyObject().(client.Object)
patch := client.MergeFrom(newObj)
Expand Down
2 changes: 2 additions & 0 deletions internal/burrito/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type ControllerTimers struct {
OnError time.Duration `mapstructure:"onError"`
WaitAction time.Duration `mapstructure:"waitAction"`
FailureGracePeriod time.Duration `mapstructure:"failureGracePeriod"`
RepositorySync time.Duration `mapstructure:"repositorySync"`
}

type RepositoryConfig struct {
Expand Down Expand Up @@ -233,6 +234,7 @@ func TestConfig() *Config {
WaitAction: 5 * time.Minute,
FailureGracePeriod: 15 * time.Second,
OnError: 1 * time.Minute,
RepositorySync: 5 * time.Minute,
},
},
Runner: RunnerConfig{
Expand Down
11 changes: 7 additions & 4 deletions internal/controllers/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ func (c *Controllers) Exec() {
panic(err.Error())
}

log.Infof("starting these controllers: %v", c.config.Controller.Types)

for _, ctrlType := range c.config.Controller.Types {
switch ctrlType {
case "layer":
Expand All @@ -123,10 +125,11 @@ func (c *Controllers) Exec() {
log.Infof("layer controller started successfully")
case "repository":
if err = (&terraformrepository.Reconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("Burrito"),
Config: c.config,
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("Burrito"),
Config: c.config,
Datastore: datastoreClient,
}).SetupWithManager(mgr); err != nil {
log.Fatalf("unable to create repository controller: %s", err)
}
Expand Down
12 changes: 3 additions & 9 deletions internal/controllers/terraformpullrequest/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package terraformpullrequest
import (
"context"
"fmt"
"strconv"

"github.com/google/go-cmp/cmp"
"github.com/padok-team/burrito/internal/burrito/config"
Expand All @@ -24,6 +23,7 @@ import (
configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1"
"github.com/padok-team/burrito/internal/utils/gitprovider"
gt "github.com/padok-team/burrito/internal/utils/gitprovider/types"
"github.com/padok-team/burrito/internal/utils/typeutils"
)

// Reconciler reconciles a TerraformPullRequest object
Expand Down Expand Up @@ -147,7 +147,6 @@ func (r *Reconciler) initializeProvider(ctx context.Context, repository *configv
log.Debugf("no secret configured for repository %s/%s, skipping provider initialization", repository.Namespace, repository.Name)
return nil, nil
}
log.Infof("KUBE API REQUEST: getting secret %s/%s", repository.Namespace, repository.Spec.Repository.SecretName)
secret := &corev1.Secret{}
err := r.Client.Get(ctx, types.NamespacedName{
Name: repository.Spec.Repository.SecretName,
Expand All @@ -158,9 +157,9 @@ func (r *Reconciler) initializeProvider(ctx context.Context, repository *configv
return nil, err
}
config := gitprovider.Config{
AppID: parseSecretInt64(secret.Data["githubAppId"]),
AppID: typeutils.ParseSecretInt64(secret.Data["githubAppId"]),
URL: repository.Spec.Repository.Url,
AppInstallationID: parseSecretInt64(secret.Data["githubAppInstallationId"]),
AppInstallationID: typeutils.ParseSecretInt64(secret.Data["githubAppInstallationId"]),
AppPrivateKey: string(secret.Data["githubAppPrivateKey"]),
GitHubToken: string(secret.Data["githubToken"]),
GitLabToken: string(secret.Data["gitlabToken"]),
Expand Down Expand Up @@ -205,8 +204,3 @@ func (r *Reconciler) initializeDefaultProviders() error {
}
return nil
}

func parseSecretInt64(data []byte) int64 {
v, _ := strconv.ParseInt(string(data), 10, 64)
return v
}
Loading
Loading