controllers/gerritproject/syncer.go (130 lines of code) (raw):
package gerritproject
import (
"context"
"fmt"
"strings"
"time"
"github.com/pkg/errors"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
gerritApi "github.com/epam/edp-gerrit-operator/v2/api/v1"
gerritClient "github.com/epam/edp-gerrit-operator/v2/pkg/client/gerrit"
)
const syncRetries = 3
func (r *Reconcile) syncBackendProjects(interval time.Duration) {
ticker := time.Tick(interval)
for range ticker {
for i := 0; i < syncRetries; i++ {
if err := r.syncBackendProjectsTick(); err != nil {
r.log.Error(err, "unable to sync gerrit projects")
continue
}
break
}
}
}
func (r *Reconcile) syncBackendProjectsTick() error {
var (
gerritList gerritApi.GerritList
gerritProjectList gerritApi.GerritProjectList
ctx = context.Background()
)
if err := r.client.List(ctx, &gerritList); err != nil {
return errors.Wrap(err, "unable to list gerrits")
}
if err := r.client.List(ctx, &gerritProjectList); err != nil {
return errors.Wrap(err, "unable to list gerrit projects")
}
for i := 0; i < len(gerritList.Items); i++ {
if err := r.syncGerritInstance(ctx, &gerritList.Items[i], gerritProjectList.Items); err != nil {
return errors.Wrapf(err, "unable to sync gerrit instance: %s", gerritList.Items[i].Name)
}
}
return nil
}
func (r *Reconcile) syncGerritInstance(ctx context.Context, gr *gerritApi.Gerrit,
allK8sGerritProjects []gerritApi.GerritProject,
) error {
cl, err := r.service.GetRestClient(gr)
if err != nil {
return errors.Wrap(err, "unable to init gerrit client")
}
backendProjects, err := cl.ListProjects("CODE")
if err != nil {
return errors.Wrap(err, "unable to list projects from gerrit")
}
k8sProjects := filterGerritProjectsByGerrit(gr, allK8sGerritProjects)
for _, backendProject := range backendProjects {
k8sProject, ok := k8sProjects[backendProject.Name]
if !ok {
k8sProject, err = r.createGerritProject(ctx, gr, &backendProject)
if err != nil {
return errors.Wrap(err, "unable to create gerrit project")
}
}
if err := r.syncProjectBranches(ctx, cl, k8sProject); err != nil {
return errors.Wrap(err, "unable to sync gerrit project branches")
}
}
return nil
}
func (r *Reconcile) syncProjectBranches(ctx context.Context, cl gerritClient.ClientInterface,
k8sProject *gerritApi.GerritProject,
) error {
branches, err := cl.ListProjectBranches(k8sProject.Spec.Name)
if err != nil {
return errors.Wrap(err, "unable to list project branches")
}
// reload gerrit project to prevent conflict with gerrit project operator
var prj gerritApi.GerritProject
if err := r.client.Get(ctx, types.NamespacedName{
Name: k8sProject.Name,
Namespace: k8sProject.Namespace,
}, &prj); err != nil {
return errors.Wrap(err, "unable to get gerrit project")
}
prj.Status.Branches = make([]string, 0, len(branches))
for _, br := range branches {
prj.Status.Branches = append(prj.Status.Branches, br.Ref)
}
if err := r.client.Status().Update(ctx, &prj); err != nil {
return errors.Wrap(err, "unable to update gerrit project")
}
return nil
}
func (r *Reconcile) createGerritProject(ctx context.Context, gr *gerritApi.Gerrit,
backendProject *gerritClient.Project,
) (*gerritApi.GerritProject, error) {
prj := gerritApi.GerritProject{
ObjectMeta: metaV1.ObjectMeta{
Name: strings.ToLower(fmt.Sprintf("%s-%s", gr.Name, backendProject.SlugifyName())),
Namespace: gr.Namespace,
},
Spec: gerritApi.GerritProjectSpec{
Name: backendProject.Name,
Parent: backendProject.Parent,
Description: backendProject.Description,
SubmitType: backendProject.SubmitType,
Owners: backendProject.Owners,
RejectEmptyCommit: backendProject.RejectEmptyCommit,
PermissionsOnly: backendProject.PermissionsOnly,
CreateEmptyCommit: backendProject.CreateEmptyCommit,
Branches: backendProject.Branches,
OwnerName: gr.Name,
},
}
if err := r.client.Create(ctx, &prj); err != nil {
return nil, errors.Wrap(err, "unable to create gerrit project")
}
return &prj, nil
}
func filterGerritProjectsByGerrit(g *gerritApi.Gerrit, projects []gerritApi.GerritProject) map[string]*gerritApi.GerritProject {
result := make(map[string]*gerritApi.GerritProject)
for i := 0; i < len(projects); i++ {
for _, owner := range projects[i].OwnerReferences {
if owner.UID == g.UID && owner.Kind == g.Kind {
result[projects[i].Spec.Name] = &projects[i]
}
}
}
return result
}