github.com/jenkins-x/jx/v2@v2.1.155/pkg/kube/git_services.go (about)

     1  package kube
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/url"
     7  	"strings"
     8  
     9  	"github.com/jenkins-x/jx-logging/pkg/log"
    10  	"github.com/jenkins-x/jx/v2/pkg/auth"
    11  	"github.com/jenkins-x/jx/v2/pkg/kube/naming"
    12  
    13  	"github.com/pkg/errors"
    14  
    15  	v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1"
    16  	"github.com/jenkins-x/jx-api/pkg/client/clientset/versioned"
    17  	"github.com/jenkins-x/jx/v2/pkg/gits"
    18  	"k8s.io/client-go/kubernetes"
    19  
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  )
    22  
    23  // EnsureGitServiceExistsForHost ensures that there is a GitService CRD for the given host and kind
    24  func EnsureGitServiceExistsForHost(jxClient versioned.Interface, devNs string, kind string, name string, gitUrl string, out io.Writer) error {
    25  	if kind == "" || (kind == "github" && gitUrl == gits.GitHubURL) || gitUrl == "" {
    26  		return nil
    27  	}
    28  
    29  	gitServices := jxClient.JenkinsV1().GitServices(devNs)
    30  	list, err := gitServices.List(metav1.ListOptions{})
    31  	if err != nil {
    32  		return errors.Wrap(err, "failed to list git services")
    33  	}
    34  	for _, g := range list.Items {
    35  		gs := g
    36  		if gitUrlsEqual(gs.Spec.URL, gitUrl) {
    37  			oldKind := gs.Spec.GitKind
    38  			if oldKind != kind {
    39  				fmt.Fprintf(out, "Updating GitService %s as the kind has changed from %s to %s\n", gs.Name, oldKind, kind)
    40  				gs.Spec.GitKind = kind
    41  				_, err = gitServices.PatchUpdate(&gs)
    42  				if err != nil {
    43  					return fmt.Errorf("Failed to update kind on GitService with name %s: %s", gs.Name, err)
    44  				}
    45  				return errors.Wrap(err, "failed to PatchUpdate")
    46  			} else {
    47  				log.Logger().Infof("already has GitService %s in namespace %s for URL %s", gs.Name, devNs, gitUrl)
    48  				return nil
    49  			}
    50  		}
    51  	}
    52  	if name == "" {
    53  		u, err := url.Parse(gitUrl)
    54  		if err != nil {
    55  			return errors.Wrapf(err, "no name supplied and could not parse URL %s", u)
    56  		}
    57  		name = u.Host
    58  	}
    59  
    60  	// not found so lets create a new GitService
    61  	gitSvc := &v1.GitService{
    62  		ObjectMeta: metav1.ObjectMeta{
    63  			Name: naming.ToValidNameWithDots(name),
    64  		},
    65  		Spec: v1.GitServiceSpec{
    66  			Name:    name,
    67  			URL:     gitUrl,
    68  			GitKind: kind,
    69  		},
    70  	}
    71  	current, err := gitServices.Get(name, metav1.GetOptions{})
    72  	if err != nil {
    73  		_, err = gitServices.Create(gitSvc)
    74  		if err != nil {
    75  			return errors.Wrapf(err, "failed to create GitService with name %s", gitSvc.Name)
    76  		}
    77  		log.Logger().Infof("GitService %s created in namespace %s for URL %s", gitSvc.Name, devNs, gitUrl)
    78  	} else if current != nil {
    79  		if current.Spec.URL != gitSvc.Spec.URL || current.Spec.GitKind != gitSvc.Spec.GitKind {
    80  			current.Spec.URL = gitSvc.Spec.URL
    81  			current.Spec.GitKind = gitSvc.Spec.GitKind
    82  
    83  			_, err = gitServices.PatchUpdate(current)
    84  			if err != nil {
    85  				return errors.Wrapf(err, "failed to PatchUpdate GitService with name %s", gitSvc.Name)
    86  			}
    87  			log.Logger().Infof("GitService %s updated in namespace %s for URL %s", gitSvc.Name, devNs, gitUrl)
    88  		}
    89  	}
    90  	return nil
    91  }
    92  
    93  // GetGitServiceKind returns the kind of the given host if one can be found or ""
    94  func GetGitServiceKind(jxClient versioned.Interface, kubeClient kubernetes.Interface, devNs string, clusterAuthConfig *auth.AuthConfig, gitServiceURL string) (string, error) {
    95  	answer := gits.SaasGitKind(gitServiceURL)
    96  	if answer != "" {
    97  		return answer, nil
    98  	}
    99  
   100  	if clusterAuthConfig != nil {
   101  		clusterServer := clusterAuthConfig.GetServer(gitServiceURL)
   102  		if clusterServer != nil {
   103  			return clusterServer.Kind, nil
   104  		}
   105  	}
   106  
   107  	answer, err := GetServiceKindFromSecrets(kubeClient, devNs, gitServiceURL)
   108  	if err == nil && answer != "" {
   109  		return answer, nil
   110  	}
   111  
   112  	return getServiceKindFromGitServices(jxClient, devNs, gitServiceURL)
   113  }
   114  
   115  // GetServiceKindFromSecrets gets the kind of service from secrets
   116  func GetServiceKindFromSecrets(kubeClient kubernetes.Interface, ns string, gitServiceURL string) (string, error) {
   117  	secretList, err := kubeClient.CoreV1().Secrets(ns).List(metav1.ListOptions{})
   118  	if err != nil {
   119  		return "", errors.Wrap(err, "failed to list the secrets")
   120  	}
   121  
   122  	// note sometimes the Git secret is just called 'jx-pipeline-git' if its created as part of
   123  	// 'jx create cluster --git-provider-url' - so lets handle the missing - on the name
   124  	secretNamePrefix := strings.TrimSuffix(SecretJenkinsPipelineGitCredentials, "-")
   125  
   126  	for _, secret := range secretList.Items {
   127  		if strings.HasPrefix(secret.GetName(), secretNamePrefix) {
   128  			annotations := secret.GetAnnotations()
   129  			url, ok := annotations[AnnotationURL]
   130  			if !ok {
   131  				continue
   132  			}
   133  			if gitUrlsEqual(url, gitServiceURL) {
   134  				labels := secret.GetLabels()
   135  				serviceKind, ok := labels[LabelServiceKind]
   136  				if !ok {
   137  					return "", fmt.Errorf("no service kind label found on secret '%s' for Git service '%s'",
   138  						secret.GetName(), gitServiceURL)
   139  				}
   140  				if serviceKind == "" {
   141  					kind := labels[LabelKind]
   142  					if kind == "git" {
   143  						serviceKind = gits.SaasGitKind(gitServiceURL)
   144  						if serviceKind == "" {
   145  							// lets default to github?
   146  							serviceKind = gits.KindGitHub
   147  						}
   148  					}
   149  				}
   150  				return serviceKind, nil
   151  			}
   152  		}
   153  	}
   154  	return "", fmt.Errorf("no secret found with configuration for '%s' Git service", gitServiceURL)
   155  }
   156  
   157  func getServiceKindFromGitServices(jxClient versioned.Interface, ns string, gitServiceURL string) (string, error) {
   158  	gitServices := jxClient.JenkinsV1().GitServices(ns)
   159  	list, err := gitServices.List(metav1.ListOptions{})
   160  	if err == nil {
   161  		for _, gs := range list.Items {
   162  			if gitUrlsEqual(gs.Spec.URL, gitServiceURL) {
   163  				return gs.Spec.GitKind, nil
   164  			}
   165  		}
   166  	}
   167  	return "", fmt.Errorf("no Git service resource found with URL '%s' in namespace %s", gitServiceURL, ns)
   168  }
   169  
   170  func gitUrlsEqual(url1 string, url2 string) bool {
   171  	return url1 == url2 || strings.TrimSuffix(url1, "/") == strings.TrimSuffix(url2, "/")
   172  }