Skip to content
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
2 changes: 1 addition & 1 deletion cmd/argocd/commands/admin/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func NewGenAppSpecCommand() *cobra.Command {
argocd admin app generate-spec kasane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane
`,
Run: func(c *cobra.Command, args []string) {
apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags(), false)
errors.CheckError(err)
if len(apps) > 1 {
errors.CheckError(fmt.Errorf("failed to generate spec, more than one application is not supported"))
Expand Down
95 changes: 70 additions & 25 deletions cmd/argocd/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (

"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless"
cmdutil "github.com/argoproj/argo-cd/v2/cmd/util"
argocommon "github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/controller"
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
Expand All @@ -51,6 +52,7 @@ import (
argoio "github.com/argoproj/argo-cd/v2/util/io"
"github.com/argoproj/argo-cd/v2/util/manifeststream"
"github.com/argoproj/argo-cd/v2/util/text/label"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// NewApplicationCommand returns a new instance of an `argocd app` command
Expand Down Expand Up @@ -139,7 +141,7 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.

argocdClient := headless.NewClientOrDie(clientOpts, c)

apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags())
apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags(), false)
errors.CheckError(err)

for _, app := range apps {
Expand Down Expand Up @@ -2344,10 +2346,12 @@ func printOperationResult(opState *argoappv1.OperationState) {
// NewApplicationManifestsCommand returns a new instance of an `argocd app manifests` command
func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
source string
revision string
local string
localRepoRoot string
source string
revision string
local string
localRepoRoot string
localAppManifest string
kubeVersion string
)
var command = &cobra.Command{
Use: "manifests APPNAME",
Expand All @@ -2360,35 +2364,56 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
os.Exit(1)
}
appName, appNs := argo.ParseFromQualifiedName(args[0], "")
clientset := headless.NewClientOrDie(clientOpts, c)
conn, appIf := clientset.NewApplicationClientOrDie()
defer argoio.Close(conn)
resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{
ApplicationName: &appName,
AppNamespace: &appNs,
})
errors.CheckError(err)

var unstructureds []*unstructured.Unstructured
switch source {
case "git":
if local != "" {
app, err := appIf.Get(context.Background(), &application.ApplicationQuery{Name: &appName})
errors.CheckError(err)
if localAppManifest != "" {
// get app from file
apps, err := cmdutil.ConstructApps(localAppManifest, "", []string{}, []string{}, args, cmdutil.AppOptions{}, c.Flags(), true)
errors.CheckError(err)
KustomizeOptions := argoappv1.KustomizeOptions{BuildOptions: "--enable-helm --load-restrictor=LoadRestrictionsNone"}

for _, app := range apps {
projSources := []string{app.Spec.Source.RepoURL}
proj := &argoappv1.AppProject{
Spec: argoappv1.AppProjectSpec{
SourceRepos: projSources,
},
ObjectMeta: metav1.ObjectMeta{
Name: app.Spec.Project,
},
}

settingsConn, settingsIf := clientset.NewSettingsClientOrDie()
defer argoio.Close(settingsConn)
argoSettings, err := settingsIf.Get(context.Background(), &settings.SettingsQuery{})
errors.CheckError(err)
unstructureds = getLocalObjects(context.Background(), app, proj, local, localRepoRoot, argocommon.LabelKeyAppInstance, kubeVersion, []string{""}, &KustomizeOptions, "")
}
} else {
clientset := headless.NewClientOrDie(clientOpts, c)
conn, appIf := clientset.NewApplicationClientOrDie()
defer argoio.Close(conn)

clusterConn, clusterIf := clientset.NewClusterClientOrDie()
defer argoio.Close(clusterConn)
cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
errors.CheckError(err)
app, err := appIf.Get(context.Background(), &application.ApplicationQuery{Name: &appName})
errors.CheckError(err)

proj := getProject(c, clientOpts, ctx, app.Spec.Project)
unstructureds = getLocalObjects(context.Background(), app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod)
settingsConn, settingsIf := clientset.NewSettingsClientOrDie()
defer argoio.Close(settingsConn)
argoSettings, err := settingsIf.Get(context.Background(), &settings.SettingsQuery{})
errors.CheckError(err)

clusterConn, clusterIf := clientset.NewClusterClientOrDie()
defer argoio.Close(clusterConn)
cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
errors.CheckError(err)

proj := getProject(c, clientOpts, ctx, app.Spec.Project)
unstructureds = getLocalObjects(context.Background(), app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod)
}
} else if revision != "" {
clientset := headless.NewClientOrDie(clientOpts, c)
conn, appIf := clientset.NewApplicationClientOrDie()
defer argoio.Close(conn)

q := application.ApplicationManifestQuery{
Name: &appName,
AppNamespace: &appNs,
Expand All @@ -2403,11 +2428,29 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
unstructureds = append(unstructureds, obj)
}
} else {
clientset := headless.NewClientOrDie(clientOpts, c)
conn, appIf := clientset.NewApplicationClientOrDie()
defer argoio.Close(conn)
resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{
ApplicationName: &appName,
AppNamespace: &appNs,
})
errors.CheckError(err)

targetObjs, err := targetObjects(resources.Items)
errors.CheckError(err)
unstructureds = targetObjs
}
case "live":
clientset := headless.NewClientOrDie(clientOpts, c)
conn, appIf := clientset.NewApplicationClientOrDie()
defer argoio.Close(conn)
resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{
ApplicationName: &appName,
AppNamespace: &appNs,
})
errors.CheckError(err)

liveObjs, err := cmdutil.LiveObjects(resources.Items)
errors.CheckError(err)
unstructureds = liveObjs
Expand All @@ -2427,6 +2470,8 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
command.Flags().StringVar(&revision, "revision", "", "Show manifests at a specific revision")
command.Flags().StringVar(&local, "local", "", "If set, show locally-generated manifests. Value is the absolute path to app manifests within the manifest repo. Example: '/home/username/apps/env/app-1'.")
command.Flags().StringVar(&localRepoRoot, "local-repo-root", ".", "Path to the local repository root. Used together with --local allows setting the repository root. Example: '/home/username/apps'.")
command.Flags().StringVar(&localAppManifest, "local-app-manifest", "", "Path to the local app. Used together with --local and --local-repo-root allows using the local application. Example: '/home/username/apps/app-manifest.yaml'.")
command.Flags().StringVar(&kubeVersion, "kube-version", "v1.27.0", "Target kubernetes cluster version. Used together with --local-app-manifest. Example: 'v1.26.4'.")
return command
}

Expand Down
56 changes: 41 additions & 15 deletions cmd/util/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -623,36 +623,62 @@ func constructAppsBaseOnName(appName string, labels, annotations, args []string,
}, nil
}

func constructAppsFromFileUrl(fileURL, appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet) ([]*argoappv1.Application, error) {
func constructAppsFromFileUrl(fileURL, appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet, filterByAppName bool) ([]*argoappv1.Application, error) {
apps := make([]*argoappv1.Application, 0)
// read uri
err := readAppsFromURI(fileURL, &apps)
if err != nil {
return nil, err
}
filteredApps := make([]*argoappv1.Application, 0)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we can filter by application name from 1 file with multiple applications

for _, app := range apps {
if len(args) == 1 && args[0] != app.Name {
return nil, fmt.Errorf("app name '%s' does not match app spec metadata.name '%s'", args[0], app.Name)
}
if appName != "" && appName != app.Name {
app.Name = appName
if filterByAppName {
if len(args) == 1 {
if appName != "" && appName != args[0] {
return nil, fmt.Errorf("--name argument '%s' does not match app name %s", appName, args[0])
}
appName = args[0]
}

if appName == app.Name {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need a separate filterByAppName?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in case the file given as --local-app-manifest contains multiple YAML documents.

SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(app, appOpts.Parameters)
mergeLabels(app, labels)
setAnnotations(app, annotations)
filteredApps = append(filteredApps, app)
}
} else {
if len(args) == 1 && args[0] != app.Name {
return nil, fmt.Errorf("app name '%s' does not match app spec metadata.name '%s'", args[0], app.Name)
}
if appName != "" && appName != app.Name {
app.Name = appName
}
if app.Name == "" {
return nil, fmt.Errorf("app.Name is empty. --name argument can be used to provide app.Name")
}
SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(app, appOpts.Parameters)
mergeLabels(app, labels)
setAnnotations(app, annotations)
filteredApps = append(filteredApps, app)
}
if app.Name == "" {
return nil, fmt.Errorf("app.Name is empty. --name argument can be used to provide app.Name")
}

if filterByAppName {
if len(filteredApps) == 0 {
return nil, fmt.Errorf("App name '%s' does not match any app spec in '%s'", appName, fileURL)
}
SetAppSpecOptions(flags, &app.Spec, &appOpts)
SetParameterOverrides(app, appOpts.Parameters)
mergeLabels(app, labels)
setAnnotations(app, annotations)
}
return apps, nil

return filteredApps, nil
}

func ConstructApps(fileURL, appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet) ([]*argoappv1.Application, error) {
func ConstructApps(fileURL, appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet, filterByAppName bool) ([]*argoappv1.Application, error) {
if fileURL == "-" {
return constructAppsFromStdin()
} else if fileURL != "" {
return constructAppsFromFileUrl(fileURL, appName, labels, annotations, args, appOpts, flags)
return constructAppsFromFileUrl(fileURL, appName, labels, annotations, args, appOpts, flags, filterByAppName)
}
return constructAppsBaseOnName(appName, labels, annotations, args, appOpts, flags)
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/util/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ func TestConstructAppFromStdin(t *testing.T) {

os.Stdin = file

apps, err := ConstructApps("-", "test", []string{}, []string{}, []string{}, AppOptions{}, nil)
apps, err := ConstructApps("-", "test", []string{}, []string{}, []string{}, AppOptions{}, nil, false)

if err := file.Close(); err != nil {
log.Fatal(err)
Expand All @@ -334,7 +334,7 @@ func TestConstructAppFromStdin(t *testing.T) {
}

func TestConstructBasedOnName(t *testing.T) {
apps, err := ConstructApps("", "test", []string{}, []string{}, []string{}, AppOptions{}, nil)
apps, err := ConstructApps("", "test", []string{}, []string{}, []string{}, AppOptions{}, nil, false)

assert.NoError(t, err)
assert.Equal(t, 1, len(apps))
Expand Down
12 changes: 7 additions & 5 deletions docs/user-guide/commands/argocd_app_manifests.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ argocd app manifests APPNAME [flags]
### Options

```
-h, --help help for manifests
--local string If set, show locally-generated manifests. Value is the absolute path to app manifests within the manifest repo. Example: '/home/username/apps/env/app-1'.
--local-repo-root string Path to the local repository root. Used together with --local allows setting the repository root. Example: '/home/username/apps'. (default ".")
--revision string Show manifests at a specific revision
--source string Source of manifests. One of: live|git (default "git")
-h, --help help for manifests
--kube-version string Target kubernetes cluster version. Used together with --local-app-manifest. Example: 'v1.26.4'. (default "v1.27.0")
--local string If set, show locally-generated manifests. Value is the absolute path to app manifests within the manifest repo. Example: '/home/username/apps/env/app-1'.
--local-app-manifest string Path to the local app. Used together with --local and --local-repo-root allows using the local application. Example: '/home/username/apps/app-manifest.yaml'.
--local-repo-root string Path to the local repository root. Used together with --local allows setting the repository root. Example: '/home/username/apps'. (default ".")
--revision string Show manifests at a specific revision
--source string Source of manifests. One of: live|git (default "git")
```

### Options inherited from parent commands
Expand Down