Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions docs/modules/ROOT/pages/running/gitops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ spec:
container:
requestMemory: 256Mi
gitops:
enabled: true
url: https://github.com/my-org/my-camel-apps.git
secret: my-gh-token
branchPush: cicd-listener
Expand Down Expand Up @@ -154,6 +155,7 @@ spec:
- my-env=dev
...
gitops:
enabled: true
url: https://github.com/my-org/my-camel-apps.git
secret: my-gh-token
branchPush: cicd-listener-test
Expand All @@ -174,6 +176,7 @@ spec:
properties:
- my-env=test
gitops:
enabled: true
url: https://github.com/my-org/my-camel-apps.git
secret: my-gh-token
branchPush: cicd-listener-prod
Expand Down
24 changes: 24 additions & 0 deletions pkg/cmd/promote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,13 @@ spec:
status: {}
`

const allKustItContent = `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: prod-namespace
resources:
- ../../../my-it-test/overlays/prod-namespace/
`

func TestIntegrationGitOps(t *testing.T) {
srcPlatform := v1.NewIntegrationPlatform("default", platform.DefaultPlatformName)
srcPlatform.Status.Version = defaults.Version
Expand Down Expand Up @@ -609,6 +616,11 @@ func TestIntegrationGitOps(t *testing.T) {
patchIt, err := os.ReadFile(filepath.Join(tmpDir, "my-it-test", "overlays", "prod-namespace", "patch-integration.yaml"))
require.NoError(t, err)
assert.Equal(t, expectedGitOpsItPatch, string(patchIt))

// Verify also the "all" profile
allIts, err := os.ReadFile(filepath.Join(tmpDir, "all", "overlays", "prod-namespace", "kustomization.yaml"))
require.NoError(t, err)
assert.Equal(t, allKustItContent, string(allIts))
}

const expectedGitOpsPipe = `apiVersion: camel.apache.org/v1
Expand Down Expand Up @@ -696,6 +708,13 @@ spec:
status: {}
`

const allKustPipeContent = `apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: prod-namespace
resources:
- ../../../my-pipe-test/overlays/prod-namespace/
`

func TestPipeGitOps(t *testing.T) {
srcPlatform := v1.NewIntegrationPlatform("default", platform.DefaultPlatformName)
srcPlatform.Status.Version = defaults.Version
Expand Down Expand Up @@ -769,4 +788,9 @@ func TestPipeGitOps(t *testing.T) {
patchPipe, err := os.ReadFile(filepath.Join(tmpDir, "my-pipe-test", "overlays", "prod-namespace", "patch-pipe.yaml"))
require.NoError(t, err)
assert.Equal(t, expectedGitOpsPipePatch, string(patchPipe))

// Verify also the "all" profile
allPipes, err := os.ReadFile(filepath.Join(tmpDir, "all", "overlays", "prod-namespace", "kustomization.yaml"))
require.NoError(t, err)
assert.Equal(t, allKustPipeContent, string(allPipes))
}
6 changes: 3 additions & 3 deletions pkg/controller/integration/integration_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ func enqueueRequestsFromConfigFunc(ctx context.Context, c client.Client, res ctr

for _, integration := range list.Items {
found := false
if integration.Spec.Traits.Mount == nil || !ptr.Deref(integration.Spec.Traits.Mount.HotReload, false) {
if integration.Status.Traits == nil || integration.Status.Traits.Mount == nil || !ptr.Deref(integration.Status.Traits.Mount.HotReload, false) {
continue
}
for _, c := range integration.Spec.Traits.Mount.Configs {
for _, c := range integration.Status.Traits.Mount.Configs {
if conf, parseErr := utilResource.ParseConfig(c); parseErr == nil {
if conf.StorageType() == storageType && conf.Name() == res.GetName() {
found = true
Expand All @@ -225,7 +225,7 @@ func enqueueRequestsFromConfigFunc(ctx context.Context, c client.Client, res ctr
}
}
}
for _, r := range integration.Spec.Traits.Mount.Resources {
for _, r := range integration.Status.Traits.Mount.Resources {
if conf, parseErr := utilResource.ParseConfig(r); parseErr == nil {
if conf.StorageType() == storageType && conf.Name() == res.GetName() {
found = true
Expand Down
8 changes: 4 additions & 4 deletions pkg/controller/integration/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,10 @@ func isIntegrationKitResetRequired(integration *v1.Integration, kit *v1.Integrat
func getIntegrationSecretAndConfigmapResourceVersions(ctx context.Context, client client.Client, integration *v1.Integration) ([]string, []string) {
configmaps := make([]string, 0)
secrets := make([]string, 0)
if integration.Spec.Traits.Mount != nil && ptr.Deref(integration.Spec.Traits.Mount.HotReload, false) {
mergedResources := make([]string, 0)
mergedResources = append(mergedResources, integration.Spec.Traits.Mount.Configs...)
mergedResources = append(mergedResources, integration.Spec.Traits.Mount.Resources...)
if integration.Status.Traits != nil && integration.Status.Traits.Mount != nil && ptr.Deref(integration.Status.Traits.Mount.HotReload, false) {
mergedResources := make([]string, 0, len(integration.Status.Traits.Mount.Configs)+len(integration.Status.Traits.Mount.Resources))
mergedResources = append(mergedResources, integration.Status.Traits.Mount.Configs...)
mergedResources = append(mergedResources, integration.Status.Traits.Mount.Resources...)
for _, c := range mergedResources {
if conf, parseErr := utilResource.ParseConfig(c); parseErr == nil {
if conf.StorageType() == utilResource.StorageTypeConfigmap {
Expand Down
9 changes: 9 additions & 0 deletions pkg/controller/integration/monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ func TestGetIntegrationSecretAndConfigmapResourceVersions(t *testing.T) {
},
},
},
Status: v1.IntegrationStatus{
Traits: &v1.Traits{
Mount: &trait.MountTrait{
Configs: []string{"configmap:cm-test"},
Resources: []string{"secret:sec-test"},
},
},
},
}
c, err := internal.NewFakeClient(cm, sec)
assert.Nil(t, err)
Expand All @@ -82,6 +90,7 @@ func TestGetIntegrationSecretAndConfigmapResourceVersions(t *testing.T) {
assert.Len(t, secrets, 0)
// Enabled hot reload (true)
it.Spec.Traits.Mount.HotReload = ptr.To(true)
it.Status.Traits.Mount.HotReload = ptr.To(true)
configmaps, secrets = getIntegrationSecretAndConfigmapResourceVersions(context.TODO(), c, it)
assert.Len(t, configmaps, 1)
assert.Len(t, secrets, 1)
Expand Down
6 changes: 3 additions & 3 deletions pkg/controller/integrationplatform/kamelets.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"strings"

v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
"knative.dev/pkg/ptr"
"k8s.io/utils/ptr"

"github.com/apache/camel-k/v2/pkg/client"
"github.com/apache/camel-k/v2/pkg/util"
Expand Down Expand Up @@ -234,8 +234,8 @@ func loadKamelet(path string, platform *v1.IntegrationPlatform) (*v1.Kamelet, er
Kind: platform.Kind,
Name: platform.Name,
UID: platform.UID,
Controller: ptr.Bool(true),
BlockOwnerDeletion: ptr.Bool(true),
Controller: ptr.To(true),
BlockOwnerDeletion: ptr.To(true),
},
}
kamelet.SetOwnerReferences(references)
Expand Down
4 changes: 3 additions & 1 deletion pkg/controller/pipe/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ func propagateIcon(ctx context.Context, c client.Client, l log.Logger, pipe *v1.

// We must patch this here as we're changing the resource annotations and not the resource status
err = patchPipeIconAnnotations(ctx, c, pipe, icon)
l.Errorf(err, "some error happened while patching icon annotation for Pipe %q", pipe.Name)
if err != nil {
l.Errorf(err, "some error happened while patching icon annotation for Pipe %q", pipe.Name)
}
}

func findIcon(ctx context.Context, c client.Client, pipe *v1.Pipe) (string, error) {
Expand Down
2 changes: 2 additions & 0 deletions pkg/resources/config/rbac/descoped/operator-cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ rules:
- get
- list
- patch
- watch
# Service Accounts (dynamic SA creation)
- apiGroups:
- ""
Expand All @@ -203,6 +204,7 @@ rules:
- delete
- get
- list
- watch
# Required to check if a ServiceAccount can access other namespaces resources
- apiGroups:
- authorization.k8s.io
Expand Down
12 changes: 12 additions & 0 deletions pkg/resources/config/rbac/namespaced/operator-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@ rules:
verbs:
- get
- list
# Service Accounts (dynamic SA creation)
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- delete
- get
- list
- watch
# Roles and RoleBindings
- apiGroups:
- rbac.authorization.k8s.io
Expand All @@ -192,3 +203,4 @@ rules:
- get
- list
- patch
- watch
30 changes: 19 additions & 11 deletions pkg/trait/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@
}

func (t *cronTrait) Apply(e *Environment) error {
replaced := false
var err error
//nolint: nestif
if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, v1.CapabilityCron)
Expand All @@ -197,7 +199,8 @@
return nil
}
// Will change the "from" URI in order to execute the task just once
if err := t.changeSourcesCronURI(e); err != nil {
replaced, err = t.changeSourcesCronURI(e)
if err != nil {
return err
}
cronComponentArtifact := e.CamelCatalog.GetArtifactByScheme("timer")
Expand All @@ -216,18 +219,20 @@

cronJob := t.getCronJobFor(e)
e.Resources.Add(cronJob)
conditionMessage := "CronJob name is %s" + cronJob.Name
if replaced {
conditionMessage += "; notice that the routes \"from\" parameter were changed to " +
"\"" + overriddenFromURI + "\" in order to be able to trigger the Camel application as a CronJob."
}

e.Integration.Status.SetCondition(
v1.IntegrationConditionCronJobAvailable,
corev1.ConditionTrue,
v1.IntegrationConditionCronJobAvailableReason,
fmt.Sprintf(
"CronJob name is %s. Notice that the routes \"from\" parameter was changed to "+
"\"%s\" in order to be able to trigger the Camel application as a CronJob.",
cronJob.Name,
overriddenFromURI,
))
conditionMessage,
)

}

Check failure on line 235 in pkg/trait/cron.go

View workflow job for this annotation

GitHub Actions / validate

unnecessary trailing newline (whitespace)

return nil
}
Expand Down Expand Up @@ -531,17 +536,20 @@

// changeSourcesCronURI is in charge to change the value of the from route with a component that executes
// the workload just once.
func (t *cronTrait) changeSourcesCronURI(e *Environment) error {
func (t *cronTrait) changeSourcesCronURI(e *Environment) (bool, error) {
anyRouteReplaced := false
for _, src := range e.Integration.AllSources() {
dslInspector := source.InspectorForLanguage(e.CamelCatalog, src.InferLanguage())
replaced, err := dslInspector.ReplaceFromURI(&src, overriddenFromURI)
if err != nil {
return false, fmt.Errorf("wasn't able to replace cron uri trigger in source %s", src.Name)
}
if replaced {
anyRouteReplaced = replaced
// replace generated source
e.Integration.Status.AddOrReplaceGeneratedSources(src)
} else if err != nil {
return fmt.Errorf("wasn't able to replace cron uri trigger in source %s", src.Name)
}
}

return nil
return anyRouteReplaced, nil
}
25 changes: 23 additions & 2 deletions pkg/trait/gitops.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/apache/camel-k/v2/pkg/util/io"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"

git "github.com/go-git/go-git/v5"
Expand Down Expand Up @@ -117,7 +118,10 @@ func (t *gitOpsTrait) pushGitOpsItInGitRepo(ctx context.Context, it *v1.Integrat
nowDate := time.Now().Format("20060102-150405")
branchName := t.BranchPush
if branchName == "" {
branchName = "cicd/candidate-release-" + nowDate
// NOTE: this is important to guarantee idempotency. We make sure not to create
// more than one branch from different reconciliation cycles.
branchNameDate := it.Status.DeploymentTimestamp.Format("20060102-150405")
branchName = "cicd/candidate-release-" + branchNameDate
}
commitMessage := "feat(ci): build completed on " + nowDate
branchRef := plumbing.NewBranchReferenceName(branchName)
Expand Down Expand Up @@ -175,9 +179,26 @@ func (t *gitOpsTrait) pushGitOpsItInGitRepo(ctx context.Context, it *v1.Integrat
RefSpecs: []config.RefSpec{
config.RefSpec(branchRef + ":" + branchRef),
},
// Note: this is needed to make the task idempotent without returning any error.
// Even if more parallel reconciliations are kicked off, we always push the same content,
// possibly more than once, without risking to raise an error.
Force: true,
}

return repo.Push(gitPushOptions)
err = repo.Push(gitPushOptions)
if err != nil {
return err
}

// Publish a condition to notify the change was pushed to the branch
it.Status.SetCondition(
v1.IntegrationConditionType("GitPushed"),
corev1.ConditionTrue,
"PushedToGit",
"Integration changes pushed to branch "+branchName,
)

return nil
}

// gitConf returns the git repo configuration where to pull the project from. If no value is provided, then, it takes
Expand Down
13 changes: 10 additions & 3 deletions pkg/trait/gitops_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,19 @@ import (
"time"

v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
"knative.dev/pkg/ptr"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/go-git/go-git/v5/plumbing/object"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/utils/ptr"

git "github.com/go-git/go-git/v5"
)

func TestGitOpsAddAction(t *testing.T) {
trait, _ := newGitOpsTrait().(*gitOpsTrait)
trait.Enabled = ptr.Bool(true)
trait.Enabled = ptr.To(true)
env := &Environment{
Integration: &v1.Integration{
Status: v1.IntegrationStatus{
Expand Down Expand Up @@ -72,12 +73,18 @@ func TestGitOpsPushRepoDefault(t *testing.T) {
Git: conf,
Sources: []v1.SourceSpec{v1.NewSourceSpec("Test.java", "bogus, irrelevant for test", v1.LanguageJavaSource)},
}
now := metav1.Now().Rfc3339Copy()
it.Status = v1.IntegrationStatus{
Image: "my-img-recently-baked",
Image: "my-img-recently-baked",
DeploymentTimestamp: &now,
}

err = trait.pushGitOpsItInGitRepo(context.TODO(), &it, tmpGitDir, "fake")
require.NoError(t, err)
assert.Contains(t,
it.Status.GetCondition(v1.IntegrationConditionType("GitPushed")).Message,
"Integration changes pushed to branch cicd/candidate-release",
)

lastCommitMessage, err := getLastCommitMessage(tmpGitDir)
require.NoError(t, err)
Expand Down
6 changes: 3 additions & 3 deletions pkg/trait/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func (t *mountTrait) configureCamelVolumesAndMounts(e *Environment, vols *[]core

// mountResource add the resource to volumes and mounts and return the final path where the resource is mounted.
func (t *mountTrait) mountResource(vols *[]corev1.Volume, mnts *[]corev1.VolumeMount, icnts *[]corev1.Container, conf *utilResource.Config) string {
refName := sanitizeVolumeName(conf.Name(), vols)
refName, confName := sanitizeVolumeName(conf.Name(), vols)
dstDir := conf.DestinationPath()
dstFile := ""
if conf.DestinationPath() != "" {
Expand All @@ -326,8 +326,8 @@ func (t *mountTrait) mountResource(vols *[]corev1.Volume, mnts *[]corev1.VolumeM
dstFile = conf.Key()
}
}
vol := getVolume(refName, string(conf.StorageType()), refName, conf.Key(), dstFile)
mntPath := getMountPoint(refName, dstDir, string(conf.StorageType()), string(conf.ContentType()))
vol := getVolume(refName, string(conf.StorageType()), confName, conf.Key(), dstFile)
mntPath := getMountPoint(confName, dstDir, string(conf.StorageType()), string(conf.ContentType()))
readOnly := (conf.StorageType() != utilResource.StorageTypePVC)

mnt := getMount(refName, mntPath, dstFile, readOnly)
Expand Down
Loading
Loading