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

Namespace support #672

Closed
wants to merge 4 commits into from
Closed
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
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type ImageUpdaterConfig struct {
GitCommitMail string
GitCommitMessage *template.Template
DisableKubeEvents bool
Namespaced bool
}

// newRootCommand implements the root command of argocd-image-updater
Expand Down
13 changes: 11 additions & 2 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/argoproj-labs/argocd-image-updater/pkg/registry"
"github.com/argoproj-labs/argocd-image-updater/pkg/version"

v1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/spf13/cobra"

"golang.org/x/sync/semaphore"
Expand Down Expand Up @@ -108,7 +110,11 @@ func newRunCommand() *cobra.Command {
var err error
if !disableKubernetes {
ctx := context.Background()
cfg.KubeClient, err = getKubeConfig(ctx, cfg.ArgocdNamespace, kubeConfig)
ns := cfg.ArgocdNamespace
if !cfg.Namespaced {
ns = v1.NamespaceAll
}
cfg.KubeClient, err = getKubeConfig(ctx, ns, cfg.Namespaced, kubeConfig)
if err != nil {
log.Fatalf("could not create K8s client: %v", err)
}
Expand All @@ -125,13 +131,15 @@ func newRunCommand() *cobra.Command {
cfg.ClientOpts.AuthToken = token
}

log.Infof("ArgoCD configuration: [apiKind=%s, server=%s, auth_token=%v, insecure=%v, grpc_web=%v, plaintext=%v]",
log.Infof("ArgoCD configuration: [apiKind=%s, server=%s, auth_token=%v, insecure=%v, grpc_web=%v, plaintext=%v, namespaced=%v, namespace=%s]",
cfg.ApplicationsAPIKind,
cfg.ClientOpts.ServerAddr,
cfg.ClientOpts.AuthToken != "",
cfg.ClientOpts.Insecure,
cfg.ClientOpts.GRPCWeb,
cfg.ClientOpts.Plaintext,
cfg.Namespaced,
cfg.ArgocdNamespace,
)

// Health server will start in a go routine and run asynchronously
Expand Down Expand Up @@ -223,6 +231,7 @@ func newRunCommand() *cobra.Command {
runCmd.Flags().StringVar(&cfg.GitCommitMail, "git-commit-email", env.GetStringVal("GIT_COMMIT_EMAIL", "[email protected]"), "E-Mail address to use for Git commits")
runCmd.Flags().StringVar(&commitMessagePath, "git-commit-message-path", defaultCommitTemplatePath, "Path to a template to use for Git commit messages")
runCmd.Flags().BoolVar(&cfg.DisableKubeEvents, "disable-kube-events", env.GetBoolVal("IMAGE_UPDATER_KUBE_EVENTS", false), "Disable kubernetes events")
runCmd.Flags().BoolVar(&cfg.Namespaced, "namespaced", env.GetBoolVal("IMAGE_UPDATER_NAMESPACED", true), "Scope to only the provided namespace")

return runCmd
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ argocd-image-updater test nginx --allow-tags '^1.19.\d+(\-.*)*$' --update-strate
var err error
if !disableKubernetes {
ctx := context.Background()
kubeClient, err = getKubeConfig(ctx, "", kubeConfig)
kubeClient, err = getKubeConfig(ctx, "", true, kubeConfig)
if err != nil {
log.Fatalf("could not create K8s client: %v", err)
}
Expand Down
8 changes: 4 additions & 4 deletions cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func getPrintableHealthPort(port int) string {
}
}

func getKubeConfig(ctx context.Context, namespace string, kubeConfig string) (*kube.KubernetesClient, error) {
func getKubeConfig(ctx context.Context, namespace string, namespaced bool, kubeConfig string) (*kube.KubernetesClient, error) {
var fullKubeConfigPath string
var kubeClient *kube.KubernetesClient
var err error
Expand All @@ -39,12 +39,12 @@ func getKubeConfig(ctx context.Context, namespace string, kubeConfig string) (*k
}

if fullKubeConfigPath != "" {
log.Debugf("Creating Kubernetes client from %s", fullKubeConfigPath)
log.Debugf("Creating Kubernetes client from %s for namespace '%s'", fullKubeConfigPath, namespace)
} else {
log.Debugf("Creating in-cluster Kubernetes client")
log.Debugf("Creating in-cluster Kubernetes client for namespace '%s'", namespace)
}

kubeClient, err = kube.NewKubernetesClientFromConfig(ctx, namespace, fullKubeConfigPath)
kubeClient, err = kube.NewKubernetesClientFromConfig(ctx, namespace, namespaced, fullKubeConfigPath)
if err != nil {
return nil, err
}
Expand Down
17 changes: 9 additions & 8 deletions pkg/argocd/argocd.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,41 +176,40 @@ func FilterApplicationsForUpdate(apps []v1alpha1.Application, patterns []string,
var appsForUpdate = make(map[string]ApplicationImages)

for _, app := range apps {
logCtx := log.WithContext().AddField("application", app.GetName())

logCtx := log.WithContext().AddField("application", app.GetName()).AddField("namespace", app.GetNamespace())
sourceType := getApplicationSourceType(&app)

// Check whether application has our annotation set
annotations := app.GetAnnotations()
if _, ok := annotations[common.ImageUpdaterAnnotation]; !ok {
logCtx.Tracef("skipping app '%s' of type '%s' because required annotation is missing", app.GetName(), sourceType)
logCtx.Tracef("skipping app '%s' of type '%s' because required annotation is missing", app.QualifiedName(), sourceType)
continue
}

// Check for valid application type
if !IsValidApplicationType(&app) {
logCtx.Warnf("skipping app '%s' of type '%s' because it's not of supported source type", app.GetName(), sourceType)
logCtx.Warnf("skipping app '%s' of type '%s' because it's not of supported source type", app.QualifiedName(), sourceType)
continue
}

// Check if application name matches requested patterns
if !nameMatchesPattern(app.GetName(), patterns) {
logCtx.Debugf("Skipping app '%s' because it does not match requested patterns", app.GetName())
logCtx.Debugf("Skipping app '%s' because it does not match requested patterns", app.QualifiedName())
continue
}

// Check if application carries requested label
if !matchAppLabels(app.GetName(), app.GetLabels(), appLabel) {
logCtx.Debugf("Skipping app '%s' because it does not carry requested label", app.GetName())
logCtx.Debugf("Skipping app '%s' because it does not carry requested label", app.QualifiedName())
continue
}

logCtx.Tracef("processing app '%s' of type '%v'", app.GetName(), sourceType)
logCtx.Tracef("processing app '%s' of type '%v'", app.QualifiedName(), sourceType)
imageList := parseImageList(annotations)
appImages := ApplicationImages{}
appImages.Application = app
appImages.Images = *imageList
appsForUpdate[app.GetName()] = appImages
appsForUpdate[app.QualifiedName()] = appImages
}

return appsForUpdate, nil
Expand Down Expand Up @@ -388,6 +387,7 @@ func SetHelmImage(app *v1alpha1.Application, newImage *image.ContainerImage) err
}

appName := app.GetName()
appNamespace := app.GetNamespace()

var hpImageName, hpImageTag, hpImageSpec string

Expand All @@ -407,6 +407,7 @@ func SetHelmImage(app *v1alpha1.Application, newImage *image.ContainerImage) err
log.WithContext().
AddField("application", appName).
AddField("image", newImage.GetFullNameWithoutTag()).
AddField("namespace", appNamespace).
Debugf("target parameters: image-spec=%s image-name=%s, image-tag=%s", hpImageSpec, hpImageName, hpImageTag)

mergeParams := make([]v1alpha1.HelmParameter, 0)
Expand Down
14 changes: 7 additions & 7 deletions pkg/argocd/argocd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@ func Test_FilterApplicationsForUpdate(t *testing.T) {
filtered, err := FilterApplicationsForUpdate(applicationList, []string{}, "")
require.NoError(t, err)
require.Len(t, filtered, 1)
require.Contains(t, filtered, "app1")
assert.Len(t, filtered["app1"].Images, 2)
require.Contains(t, filtered, "argocd/app1")
assert.Len(t, filtered["argocd/app1"].Images, 2)
})

t.Run("Filter for applications with patterns", func(t *testing.T) {
Expand Down Expand Up @@ -487,9 +487,9 @@ func Test_FilterApplicationsForUpdate(t *testing.T) {
filtered, err := FilterApplicationsForUpdate(applicationList, []string{"app*"}, "")
require.NoError(t, err)
require.Len(t, filtered, 2)
require.Contains(t, filtered, "app1")
require.Contains(t, filtered, "app2")
assert.Len(t, filtered["app1"].Images, 2)
require.Contains(t, filtered, "argocd/app1")
require.Contains(t, filtered, "argocd/app2")
assert.Len(t, filtered["argocd/app1"].Images, 2)
})

t.Run("Filter for applications with label", func(t *testing.T) {
Expand Down Expand Up @@ -529,8 +529,8 @@ func Test_FilterApplicationsForUpdate(t *testing.T) {
filtered, err := FilterApplicationsForUpdate(applicationList, []string{}, "custom.label/name=xyz")
require.NoError(t, err)
require.Len(t, filtered, 1)
require.Contains(t, filtered, "app1")
assert.Len(t, filtered["app1"].Images, 2)
require.Contains(t, filtered, "argocd/app1")
assert.Len(t, filtered["argocd/app1"].Images, 2)
})

}
Expand Down
7 changes: 6 additions & 1 deletion pkg/argocd/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat

result := ImageUpdaterResult{}
app := updateConf.UpdateApp.Application.GetName()
namespace := updateConf.UpdateApp.Application.GetNamespace()
changeList := make([]ChangeEntry, 0)

// Get all images that are deployed with the current application
Expand All @@ -157,7 +158,10 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat
for _, applicationImage := range updateConf.UpdateApp.Images {
updateableImage := applicationImages.ContainsImage(applicationImage, false)
if updateableImage == nil {
log.WithContext().AddField("application", app).Debugf("Image '%s' seems not to be live in this application, skipping", applicationImage.ImageName)
log.WithContext().
AddField("application", app).
AddField("namespace", namespace).
Debugf("Image '%s' seems not to be live in this application, skipping", applicationImage.ImageName)
result.NumSkipped += 1
continue
}
Expand All @@ -173,6 +177,7 @@ func UpdateApplication(updateConf *UpdateConfiguration, state *SyncIterationStat

imgCtx := log.WithContext().
AddField("application", app).
AddField("namespace", namespace).
AddField("registry", updateableImage.RegistryURL).
AddField("image_name", updateableImage.ImageName).
AddField("image_tag", updateableImage.ImageTag).
Expand Down
6 changes: 4 additions & 2 deletions pkg/kube/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"time"

"github.com/argoproj-labs/argocd-image-updater/pkg/log"
"github.com/argoproj-labs/argocd-image-updater/pkg/metrics"

appv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
Expand Down Expand Up @@ -38,7 +39,7 @@ func NewKubernetesClient(ctx context.Context, client kubernetes.Interface, appli
// NewKubernetesClient creates a new Kubernetes client object from given
// configuration file. If configuration file is the empty string, in-cluster
// client will be created.
func NewKubernetesClientFromConfig(ctx context.Context, namespace string, kubeconfig string) (*KubernetesClient, error) {
func NewKubernetesClientFromConfig(ctx context.Context, namespace string, namespaced bool, kubeconfig string) (*KubernetesClient, error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
loadingRules.ExplicitPath = kubeconfig
Expand All @@ -50,7 +51,7 @@ func NewKubernetesClientFromConfig(ctx context.Context, namespace string, kubeco
return nil, err
}

if namespace == "" {
if namespace == "" && namespaced {
namespace, _, err = clientConfig.Namespace()
if err != nil {
return nil, err
Expand All @@ -67,6 +68,7 @@ func NewKubernetesClientFromConfig(ctx context.Context, namespace string, kubeco
return nil, err
}

log.Debugf("Creating kubernetes client for ns '%s'", namespace)
return NewKubernetesClient(ctx, clientset, applicationsClientset, namespace), nil
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/kube/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import (

func Test_NewKubernetesClient(t *testing.T) {
t.Run("Get new K8s client for remote cluster instance", func(t *testing.T) {
client, err := NewKubernetesClientFromConfig(context.TODO(), "", "../../test/testdata/kubernetes/config")
client, err := NewKubernetesClientFromConfig(context.TODO(), "", true, "../../test/testdata/kubernetes/config")
require.NoError(t, err)
assert.NotNil(t, client)
assert.Equal(t, "default", client.Namespace)
})

t.Run("Get new K8s client for remote cluster instance specified namespace", func(t *testing.T) {
client, err := NewKubernetesClientFromConfig(context.TODO(), "argocd", "../../test/testdata/kubernetes/config")
client, err := NewKubernetesClientFromConfig(context.TODO(), "argocd", true, "../../test/testdata/kubernetes/config")
require.NoError(t, err)
assert.NotNil(t, client)
assert.Equal(t, "argocd", client.Namespace)
Expand Down
Loading