@@ -45,6 +45,7 @@ import (
4545 "github.com/spf13/cobra"
4646 v1 "k8s.io/api/core/v1"
4747 rbacv1 "k8s.io/api/rbac/v1"
48+ kerrors "k8s.io/apimachinery/pkg/api/errors"
4849 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4950)
5051
@@ -191,15 +192,8 @@ func NewRuntimeInstallCommand() *cobra.Command {
191192}
192193
193194func RunRuntimeInstall (ctx context.Context , opts * RuntimeInstallOptions ) error {
194- runtimes , err := cfConfig .NewClient ().V2 ().Runtime ().List (ctx )
195- if err != nil {
196- return err
197- }
198-
199- for _ , rt := range runtimes {
200- if rt .Metadata .Name == opts .RuntimeName {
201- return fmt .Errorf ("failed to create runtime: %s. A runtime by this name already exists" , opts .RuntimeName )
202- }
195+ if err := preInstallationChecks (ctx , opts ); err != nil {
196+ return fmt .Errorf ("pre installation checks failed: %w" , err )
203197 }
204198
205199 rt , err := runtime .Download (opts .Version , opts .RuntimeName )
@@ -290,6 +284,75 @@ func RunRuntimeInstall(ctx context.Context, opts *RuntimeInstallOptions) error {
290284 return nil
291285}
292286
287+ func preInstallationChecks (ctx context.Context , opts * RuntimeInstallOptions ) error {
288+ log .G (ctx ).Debug ("running pre-installation checks..." )
289+
290+ if err := checkRuntimeCollisions (ctx , opts .RuntimeName , opts .KubeFactory ); err != nil {
291+ return fmt .Errorf ("runtime collision check failed: %w" , err )
292+ }
293+
294+ if err := checkExistingRuntimes (ctx , opts .RuntimeName ); err != nil {
295+ return fmt .Errorf ("existing runtime check failed: %w" , err )
296+ }
297+
298+ return nil
299+ }
300+
301+ func checkRuntimeCollisions (ctx context.Context , runtime string , kube kube.Factory ) error {
302+ log .G (ctx ).Debug ("checking for argocd collisions in cluster" )
303+
304+ cs , err := kube .KubernetesClientSet ()
305+ if err != nil {
306+ return fmt .Errorf ("failed to build kubernetes clientset: %w" , err )
307+ }
308+
309+ crb , err := cs .RbacV1 ().ClusterRoleBindings ().Get (ctx , store .Get ().ArgoCDServerName , metav1.GetOptions {})
310+ if err != nil {
311+ if kerrors .IsNotFound (err ) {
312+ return nil // no collision
313+ }
314+
315+ return fmt .Errorf ("failed to get cluster-role-binding '%s': %w" , store .Get ().ArgoCDServerName , err )
316+ }
317+
318+ log .G (ctx ).Debug ("argocd cluster-role-binding found" )
319+
320+ if len (crb .Subjects ) == 0 {
321+ return nil // no collision
322+ }
323+
324+ subjNamespace := crb .Subjects [0 ].Namespace
325+
326+ // check if some argocd is actually using this crb
327+ _ , err = cs .AppsV1 ().Deployments (subjNamespace ).Get (ctx , store .Get ().ArgoCDServerName , metav1.GetOptions {})
328+ if err != nil {
329+ if kerrors .IsNotFound (err ) {
330+ log .G (ctx ).Debug ("argocd cluster-role-binding subject does not exist, no collision" )
331+
332+ return nil // no collision
333+ }
334+
335+ return fmt .Errorf ("failed to get deployment '%s': %w" , store .Get ().ArgoCDServerName , err )
336+ }
337+
338+ return fmt .Errorf ("argo-cd is already installed on this cluster in namespace '%s', you need to uninstall it first" , subjNamespace )
339+ }
340+
341+ func checkExistingRuntimes (ctx context.Context , runtime string ) error {
342+ runtimes , err := cfConfig .NewClient ().V2 ().Runtime ().List (ctx )
343+ if err != nil {
344+ return fmt .Errorf ("failed to list runtimes: %w" , err )
345+ }
346+
347+ for _ , rt := range runtimes {
348+ if rt .Metadata .Name == runtime {
349+ return fmt .Errorf ("runtime '%s' already exists" , runtime )
350+ }
351+ }
352+
353+ return nil
354+ }
355+
293356func intervalCheckIsRuntimePersisted (milliseconds int , ctx context.Context , runtimeName string , wg * sync.WaitGroup ) {
294357 interval := time .Duration (milliseconds ) * time .Millisecond
295358 ticker := time .NewTicker (interval )
0 commit comments