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
10 changes: 7 additions & 3 deletions cmd/argocd/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/spf13/pflag"
"github.com/yudai/gojsondiff/formatter"
"golang.org/x/crypto/ssh/terminal"
"google.golang.org/grpc/metadata"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -53,6 +54,7 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
appOpts appOptions
fileURL string
appName string
upsert bool
)
var command = &cobra.Command{
Use: "create",
Expand All @@ -64,8 +66,8 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
}
var app argoappv1.Application
if fileURL != "" {
_, err := url.ParseRequestURI(fileURL)
if err != nil {
parsedURL, err := url.ParseRequestURI(fileURL)
if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") {
err = cli.UnmarshalLocalFile(fileURL, &app)
} else {
err = cli.UnmarshalRemoteFile(fileURL, &app)
Expand Down Expand Up @@ -102,13 +104,15 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
setParameterOverrides(&app, appOpts.parameters)
conn, appIf := argocdclient.NewClientOrDie(clientOpts).NewApplicationClientOrDie()
defer util.Close(conn)
created, err := appIf.Create(context.Background(), &app)
ctx := metadata.AppendToOutgoingContext(context.Background(), "upsert", strconv.FormatBool(upsert))
created, err := appIf.Create(ctx, &app)
errors.CheckError(err)
fmt.Printf("application '%s' created\n", created.ObjectMeta.Name)
},
}
command.Flags().StringVarP(&fileURL, "file", "f", "", "Filename or URL to Kubernetes manifests for the app")
command.Flags().StringVar(&appName, "name", "", "A name for the app, ignored if a file is set")
command.Flags().BoolVar(&upsert, "upsert", false, "Allows to override application with the same name even if supplied application spec is different from existing spec")
addAppFlags(command, &appOpts)
return command
}
Expand Down
20 changes: 18 additions & 2 deletions server/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
log "github.com/sirupsen/logrus"
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"k8s.io/api/core/v1"
apierr "k8s.io/apimachinery/pkg/api/errors"
Expand Down Expand Up @@ -68,6 +69,13 @@ func (s *Server) List(ctx context.Context, q *ApplicationQuery) (*appv1.Applicat

// Create creates an application
func (s *Server) Create(ctx context.Context, a *appv1.Application) (*appv1.Application, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we just change the RPC signature to ApplicationCreateRequest instead of Application? Maybe not for 0.4.4 but for 0.5.0? Storing into context hides the API capabilities.

upsert := false
md, ok := metadata.FromIncomingContext(ctx)
if ok {
upsertMd := md["upsert"]
upsert = len(upsertMd) > 0 && upsertMd[0] == "true"
}

err := s.validateApp(ctx, &a.Spec)
if err != nil {
return nil, err
Expand All @@ -76,10 +84,18 @@ func (s *Server) Create(ctx context.Context, a *appv1.Application) (*appv1.Appli
out, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Create(a)
if apierr.IsAlreadyExists(err) {
// act idempotent if existing spec matches new spec
existing, err2 := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(a.Name, metav1.GetOptions{})
if err2 == nil {
existing, getErr := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(a.Name, metav1.GetOptions{})
if getErr != nil {
return nil, fmt.Errorf("unable to check existing application details: %v", err)
}
if upsert {
existing.Spec = a.Spec
out, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(existing)
} else {
if reflect.DeepEqual(existing.Spec, a.Spec) {
return existing, nil
} else {
return nil, fmt.Errorf("existing application spec is different, use upsert flag to force update")
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion server/application/application.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ service ApplicationService {
option (google.api.http).get = "/api/v1/applications/{name}";
}

// GetManifests returns application manifests
// GetManifests returns application manifests
rpc GetManifests(ManifestQuery) returns (repository.ManifestResponse) {
option (google.api.http).get = "/api/v1/applications/{appName}/manifests";
}
Expand Down