argocd

package
v0.2.0-beta.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 2, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

ArgoCD Engine - ArgoCD Workflow Implementation

The argocd package implements the stack.Workflow interface for ArgoCD, generating ArgoCD Application resources from Kure's domain model.

Bootstrap not implemented. GenerateBootstrap returns an error when bootstrap is enabled. If bootstrap generation is required, use the FluxCD engine instead.

Quick Start

import (
    _ "github.com/go-kure/kure/pkg/stack/argocd" // registers "argocd" provider
    "github.com/go-kure/kure/pkg/stack"
    "github.com/go-kure/kure/pkg/stack/layout"
)

Every other Go block on this page is the body of an Example function in example_test.go, which go test runs: it imports this package as argocd, stack and layout as above, k8s.io/apimachinery/pkg/apis/meta/v1/unstructured, os, path/filepath, and fmt for the lines that print what the example built. Two helpers are declared in the same file: exampleCluster() builds a cluster whose one node apps holds one bundle web with one application, which emits a ConfigMap through github.com/go-kure/kure/pkg/kubernetes and sigs.k8s.io/controller-runtime/pkg/client; printFiles(dir) prints every file below dir.

cluster := exampleCluster()
dir, err := os.MkdirTemp("", "kure-argocd-example")
if err != nil {
    panic(err)
}
defer func() { _ = os.RemoveAll(dir) }()

// Use via the stack.Workflow registry
wf, err := stack.NewWorkflow("argocd")
if err != nil {
    panic(err)
}
ml, err := wf.CreateLayoutWithResources(cluster, layout.LayoutRules{})
if err != nil {
    panic(err)
}
if err := ml.WriteToDisk(filepath.Join(dir, "clusters/prod")); err != nil {
    panic(err)
}
printFiles(dir)

Engine Construction

// Direct construction (bypasses registry)
engine := argocd.Engine()

// Configure source repository and namespace
engine.SetRepoURL("https://github.com/example/manifests.git")
engine.SetDefaultNamespace("argocd")
fmt.Println(engine.GetName(), engine.RepoURL, engine.DefaultNamespace)

Resource Generation

cluster := exampleCluster()
engine := argocd.Engine()

// Generate ArgoCD Applications from a cluster
objects, err := engine.GenerateFromCluster(cluster)
if err != nil {
    panic(err)
}
for _, obj := range objects {
    path, _, _ := unstructured.NestedString(obj.(*unstructured.Unstructured).Object, "spec", "source", "path")
    fmt.Println(obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName(), path)
}

GenerateFromCluster walks the cluster with layout.DefaultLayoutRules() and produces one ArgoCD Application (argoproj.io/v1alpha1) per directory that renders bundles, umbrella children included. Each Application's spec.source.path is that directory (layout.OriginIndex.KustomizationPath), not a path guessed from bundle names. spec.destination.server defaults to https://kubernetes.default.svc.

When a GroupFlat axis or FlattenSingleTier merges several bundles into one directory, they share one Application, as they share one Flux Kustomization (see the fluxcd package's "One Kustomization per directory"). It is named after the first bundle. Their labels are combined, and one label key with two values is an error. spec.dependencies names the Applications of the directories each bundle's DependsOn renders, and dependencies between the merged bundles are dropped. With the default rules every bundle has its own directory, so this is one Application per bundle.

Layout Integration

CreateLayoutWithResources returns the stack.ManifestLayoutResult interface; IntegrateWithLayout takes the concrete *layout.ManifestLayout behind it:

cluster := exampleCluster()
engine := argocd.Engine()

// Create layout with Applications placed in an argocd/ subdirectory
result, err := engine.CreateLayoutWithResources(cluster, layout.LayoutRules{})
if err != nil {
    panic(err)
}
ml := result.(*layout.ManifestLayout)

// Integrate Applications into an existing layout (a no-op for ArgoCD)
if err := engine.IntegrateWithLayout(ml, cluster, layout.LayoutRules{}); err != nil {
    panic(err)
}
for _, child := range ml.Children {
    fmt.Println(child.FullRepoPath(), len(child.Resources))
}

CreateLayoutWithResources generates the base manifest layout via layout.WalkCluster with the caller's rules, generates the Applications from that same layout (so every source.path is a directory it writes), then appends an argocd/ child layout containing them. The argocd/ directory sits inside the root layout's own directory, where the root's kustomization.yaml references it. An integrated FluxPlacement (FluxIntegratedPerLayout, FluxIntegratedPerBundle) is refused: the writer would then reference child layouts through Flux CRs, which an Argo layout does not have, so nothing would apply argocd/.

A KustomizationRecursive layout gets no kustomization.yaml, and the Applications do not set source.directory.recurse (go-kure/kure#144), so Argo CD applies only the manifest files at the top of such a directory.

Known Limitations

  • Bootstrap not implemented: GenerateBootstrap returns nil, nil when config is nil or disabled; returns an error when bootstrap is enabled. SupportedBootstrapModes() returns nil.
  • Applications are generated as unstructured.Unstructured objects; ArgoCD CRD types are not imported.
  • IntegrateWithLayout is a no-op (ArgoCD Applications reference external repos and do not require layout integration).
  • stack/fluxcd — full-featured FluxCD engine including bootstrap
  • stack — domain model and Workflow interface
  • stack/layout — manifest layout generation

Documentation

Overview

Example
package main

import (
	"fmt"
	"io/fs"
	"os"
	"path/filepath"

	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/go-kure/kure/pkg/kubernetes"
	"github.com/go-kure/kure/pkg/stack"
	"github.com/go-kure/kure/pkg/stack/layout"
)

// configMapApp is a minimal stack.ApplicationConfig: one ConfigMap named after
// the application.
type configMapApp struct{}

func (configMapApp) Generate(app *stack.Application) ([]*client.Object, error) {
	var obj client.Object = kubernetes.CreateConfigMap(app.Name, app.Namespace)
	return []*client.Object{&obj}, nil
}

// exampleCluster is the cluster the examples generate from: one node with one
// bundle holding one application.
func exampleCluster() *stack.Cluster {
	cluster, err := stack.NewClusterBuilder("prod").
		WithNode("apps").
		WithBundle("web").
		WithApplication("web", configMapApp{}).
		End().
		End().
		Build()
	if err != nil {
		panic(err)
	}
	return cluster
}

// printFiles prints every file below dir, relative to it.
func printFiles(dir string) {
	err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
		if err == nil && !d.IsDir() {
			rel, _ := filepath.Rel(dir, path)
			fmt.Println(rel)
		}
		return err
	})
	if err != nil {
		panic(err)
	}
}

func main() {
	cluster := exampleCluster()
	dir, err := os.MkdirTemp("", "kure-argocd-example")
	if err != nil {
		panic(err)
	}
	defer func() { _ = os.RemoveAll(dir) }()

	// Use via the stack.Workflow registry
	wf, err := stack.NewWorkflow("argocd")
	if err != nil {
		panic(err)
	}
	ml, err := wf.CreateLayoutWithResources(cluster, layout.LayoutRules{})
	if err != nil {
		panic(err)
	}
	if err := ml.WriteToDisk(filepath.Join(dir, "clusters/prod")); err != nil {
		panic(err)
	}
	printFiles(dir)
}
Output:
clusters/prod/apps/argocd/argocd-application-web.yaml
clusters/prod/apps/argocd/kustomization.yaml
clusters/prod/apps/cluster-configmap-web.yaml
clusters/prod/apps/kustomization.yaml
Example (AgentsWorkflow)
cluster := exampleCluster()

// The provider registers itself from its init, so the package has to be
// imported: import _ "github.com/go-kure/kure/pkg/stack/argocd"
wf, err := stack.NewWorkflow("argocd")
if err != nil {
	panic(err)
}
// Application paths are the directories a default-rules WalkCluster writes;
// CreateLayoutWithResources generates from the layout it walks with your rules.
apps, err := wf.GenerateFromCluster(cluster)
if err != nil {
	panic(err)
}
fmt.Println(len(apps), apps[0].GetObjectKind().GroupVersionKind().Kind, apps[0].GetName())
Output:
1 Application web

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type WorkflowEngine

type WorkflowEngine struct {
	// RepoURL is used as the source repo for generated Applications
	RepoURL string
	// DefaultNamespace is the default namespace for ArgoCD Applications
	DefaultNamespace string
}

WorkflowEngine implements the stack.Workflow interface for ArgoCD.

func Engine

func Engine() *WorkflowEngine

Engine creates an ArgoCD workflow engine.

Example
package main

import (
	"fmt"

	"github.com/go-kure/kure/pkg/stack/argocd"
)

func main() {
	// Direct construction (bypasses registry)
	engine := argocd.Engine()

	// Configure source repository and namespace
	engine.SetRepoURL("https://github.com/example/manifests.git")
	engine.SetDefaultNamespace("argocd")
	fmt.Println(engine.GetName(), engine.RepoURL, engine.DefaultNamespace)
}
Output:
ArgoCD Workflow Engine https://github.com/example/manifests.git argocd

func (*WorkflowEngine) CreateLayoutWithResources

func (w *WorkflowEngine) CreateLayoutWithResources(c *stack.Cluster, rulesInterface stack.LayoutRulesProvider) (stack.ManifestLayoutResult, error)

CreateLayoutWithResources creates a new layout that includes ArgoCD Applications.

Example
package main

import (
	"fmt"

	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/go-kure/kure/pkg/kubernetes"
	"github.com/go-kure/kure/pkg/stack"
	"github.com/go-kure/kure/pkg/stack/argocd"
	"github.com/go-kure/kure/pkg/stack/layout"
)

// configMapApp is a minimal stack.ApplicationConfig: one ConfigMap named after
// the application.
type configMapApp struct{}

func (configMapApp) Generate(app *stack.Application) ([]*client.Object, error) {
	var obj client.Object = kubernetes.CreateConfigMap(app.Name, app.Namespace)
	return []*client.Object{&obj}, nil
}

// exampleCluster is the cluster the examples generate from: one node with one
// bundle holding one application.
func exampleCluster() *stack.Cluster {
	cluster, err := stack.NewClusterBuilder("prod").
		WithNode("apps").
		WithBundle("web").
		WithApplication("web", configMapApp{}).
		End().
		End().
		Build()
	if err != nil {
		panic(err)
	}
	return cluster
}

func main() {
	cluster := exampleCluster()
	engine := argocd.Engine()

	// Create layout with Applications placed in an argocd/ subdirectory
	result, err := engine.CreateLayoutWithResources(cluster, layout.LayoutRules{})
	if err != nil {
		panic(err)
	}
	ml := result.(*layout.ManifestLayout)

	// Integrate Applications into an existing layout (a no-op for ArgoCD)
	if err := engine.IntegrateWithLayout(ml, cluster, layout.LayoutRules{}); err != nil {
		panic(err)
	}
	for _, child := range ml.Children {
		fmt.Println(child.FullRepoPath(), len(child.Resources))
	}
}
Output:
apps/argocd 1

func (*WorkflowEngine) GenerateBootstrap

func (w *WorkflowEngine) GenerateBootstrap(config *stack.BootstrapConfig, rootNode *stack.Node) ([]client.Object, error)

GenerateBootstrap creates bootstrap resources for setting up ArgoCD.

func (*WorkflowEngine) GenerateFromCluster

func (w *WorkflowEngine) GenerateFromCluster(c *stack.Cluster) ([]client.Object, error)

GenerateFromCluster creates ArgoCD Applications from a cluster definition: it walks the cluster with layout.DefaultLayoutRules and generates from that layout (see generateFromLayout), so each source.path is the directory a default-rules walk writes the bundle to. Callers writing the layout with other rules use CreateLayoutWithResources, which generates from the layout it walks.

Example
package main

import (
	"fmt"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/go-kure/kure/pkg/kubernetes"
	"github.com/go-kure/kure/pkg/stack"
	"github.com/go-kure/kure/pkg/stack/argocd"
)

// configMapApp is a minimal stack.ApplicationConfig: one ConfigMap named after
// the application.
type configMapApp struct{}

func (configMapApp) Generate(app *stack.Application) ([]*client.Object, error) {
	var obj client.Object = kubernetes.CreateConfigMap(app.Name, app.Namespace)
	return []*client.Object{&obj}, nil
}

// exampleCluster is the cluster the examples generate from: one node with one
// bundle holding one application.
func exampleCluster() *stack.Cluster {
	cluster, err := stack.NewClusterBuilder("prod").
		WithNode("apps").
		WithBundle("web").
		WithApplication("web", configMapApp{}).
		End().
		End().
		Build()
	if err != nil {
		panic(err)
	}
	return cluster
}

func main() {
	cluster := exampleCluster()
	engine := argocd.Engine()

	// Generate ArgoCD Applications from a cluster
	objects, err := engine.GenerateFromCluster(cluster)
	if err != nil {
		panic(err)
	}
	for _, obj := range objects {
		path, _, _ := unstructured.NestedString(obj.(*unstructured.Unstructured).Object, "spec", "source", "path")
		fmt.Println(obj.GetObjectKind().GroupVersionKind().Kind, obj.GetName(), path)
	}
}
Output:
Application web apps

func (*WorkflowEngine) GetName

func (w *WorkflowEngine) GetName() string

GetName returns a human-readable name for this workflow engine.

func (*WorkflowEngine) GetVersion

func (w *WorkflowEngine) GetVersion() string

GetVersion returns the version of this workflow engine.

func (*WorkflowEngine) IntegrateWithLayout

func (w *WorkflowEngine) IntegrateWithLayout(ml *layout.ManifestLayout, c *stack.Cluster, rules layout.LayoutRules) error

IntegrateWithLayout adds ArgoCD Applications to an existing manifest layout. For ArgoCD, this is typically not needed as Applications reference external repos.

func (*WorkflowEngine) SetDefaultNamespace

func (w *WorkflowEngine) SetDefaultNamespace(namespace string)

SetDefaultNamespace configures the default namespace for ArgoCD Applications.

func (*WorkflowEngine) SetRepoURL

func (w *WorkflowEngine) SetRepoURL(repoURL string)

SetRepoURL configures the repository URL for generated Applications.

func (*WorkflowEngine) SupportedBootstrapModes

func (w *WorkflowEngine) SupportedBootstrapModes() []string

SupportedBootstrapModes returns the bootstrap modes supported by ArgoCD.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL