diff --git a/pkg/cobras/helpers.go b/pkg/cobras/helpers.go index a13b0b6..d18a13d 100644 --- a/pkg/cobras/helpers.go +++ b/pkg/cobras/helpers.go @@ -1,28 +1,9 @@ package cobras import ( - "os" - "github.com/spf13/cobra" ) -// BinaryName the binary name to use in help docs -var BinaryName string - -// TopLevelCommand the top level command name -var TopLevelCommand string - -func init() { - BinaryName = os.Getenv("BINARY_NAME") - if BinaryName == "" { - BinaryName = "jx-alpha-promote" - } - TopLevelCommand = os.Getenv("TOP_LEVEL_COMMAND") - if TopLevelCommand == "" { - TopLevelCommand = "jx-alpha-promote" - } -} - // SplitCommand helper command to ignore the options object func SplitCommand(cmd *cobra.Command, options interface{}) *cobra.Command { return cmd diff --git a/pkg/cobras/templates/helpers.go b/pkg/cobras/templates/helpers.go index 913e18c..86e17fe 100644 --- a/pkg/cobras/templates/helpers.go +++ b/pkg/cobras/templates/helpers.go @@ -1,7 +1,6 @@ package templates import ( - "context" "fmt" "os" "path/filepath" @@ -9,37 +8,20 @@ import ( "strings" jxCore "github.com/jenkins-x/jx-api/v4/pkg/apis/jenkins.io/v1" - "github.com/jenkins-x/jx-api/v4/pkg/client/clientset/versioned" "github.com/jenkins-x/jx-helpers/v3/pkg/extensions" - "github.com/jenkins-x/jx-helpers/v3/pkg/kube/jxclient" - "github.com/jenkins-x/jx-logging/v3/pkg/log" - "github.com/spf13/cobra" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" ) -type Options struct { - ManagedPluginsEnabled bool - JXClient versioned.Interface - Namespace string -} - // GetPluginCommandGroups returns the plugin groups -func (o *Options) GetPluginCommandGroups(verifier extensions.PathVerifier, localPlugins []jxCore.Plugin) (PluginCommandGroups, error) { +func GetPluginCommandGroups(verifier extensions.PathVerifier, localPlugins []jxCore.Plugin) (PluginCommandGroups, error) { otherCommands := PluginCommandGroup{ Message: "Other Commands", } groups := make(map[string]PluginCommandGroup, 0) - o.addPlugins(localPlugins, &otherCommands, groups) - - err := o.addManagedPlugins(&otherCommands, groups) - if err != nil { - return nil, fmt.Errorf("failed to add managed plugins: %w", err) - } + addPlugins(localPlugins, &otherCommands, groups) pathCommands := PluginCommandGroup{ Message: "Locally Available Commands:", @@ -96,27 +78,7 @@ func (o *Options) GetPluginCommandGroups(verifier extensions.PathVerifier, local return pcgs, nil } -func (o *Options) addManagedPlugins(otherCommands *PluginCommandGroup, groups map[string]PluginCommandGroup) error { - // Managed plugins - var err error - if o.ManagedPluginsEnabled { - o.JXClient, o.Namespace, err = jxclient.LazyCreateJXClientAndNamespace(o.JXClient, o.Namespace) - if err != nil { - return fmt.Errorf("failed to create jx client: %w", err) - } - pluginList, err := o.JXClient.JenkinsV1().Plugins(o.Namespace).List(context.TODO(), metav1.ListOptions{}) - if err != nil && apierrors.IsNotFound(err) { - err = nil - } - if err != nil { - log.Logger().Debugf("failed to find Plugin CRDs in kubernetes namespace %s due to: %s", o.Namespace, err.Error()) - } - o.addPlugins(pluginList.Items, otherCommands, groups) - } - return nil -} - -func (o *Options) addPlugins(pluginSlice []jxCore.Plugin, otherCommands *PluginCommandGroup, groups map[string]PluginCommandGroup) { +func addPlugins(pluginSlice []jxCore.Plugin, otherCommands *PluginCommandGroup, groups map[string]PluginCommandGroup) { for _, plugin := range pluginSlice { pluginCommand := &PluginCommand{ PluginSpec: plugin.Spec, @@ -139,7 +101,7 @@ func (o *Options) addPlugins(pluginSlice []jxCore.Plugin, otherCommands *PluginC } // ActsAsRootCommand act as if the given set of plugins is a single root command -func ActsAsRootCommand(cmd *cobra.Command, filters []string, getPluginCommandGroups func() (PluginCommandGroups, bool), groups ...CommandGroup) FlagExposer { +func ActsAsRootCommand(cmd *cobra.Command, filters []string, getPluginCommandGroups func() PluginCommandGroups, groups ...CommandGroup) FlagExposer { if cmd == nil { panic("nil root command") } diff --git a/pkg/cobras/templates/templater.go b/pkg/cobras/templates/templater.go index b08afda..a5f1745 100644 --- a/pkg/cobras/templates/templater.go +++ b/pkg/cobras/templates/templater.go @@ -44,7 +44,7 @@ func UseOptionsTemplates(cmd *cobra.Command) { type templater struct { UsageTemplate string HelpTemplate string - GetPluginCommandGroups func() (PluginCommandGroups, bool) + GetPluginCommandGroups func() PluginCommandGroups RootCmd *cobra.Command CommandGroups Filtered []string @@ -154,7 +154,7 @@ func (t *templater) cmdGroupsString(c *cobra.Command) string { } } } - pluginCommandGroups, _ := t.GetPluginCommandGroups() + pluginCommandGroups := t.GetPluginCommandGroups() if c == t.RootCmd { for _, cmdGroup := range pluginCommandGroups { for _, cmd := range cmdGroup.Commands { diff --git a/pkg/kube/activities/activity_test.go b/pkg/kube/activities/activity_test.go index 1a39f06..d355908 100644 --- a/pkg/kube/activities/activity_test.go +++ b/pkg/kube/activities/activity_test.go @@ -14,7 +14,6 @@ import ( jxfake "github.com/jenkins-x/jx-api/v4/pkg/client/clientset/versioned/fake" typev1 "github.com/jenkins-x/jx-api/v4/pkg/client/clientset/versioned/typed/jenkins.io/v1" "github.com/jenkins-x/jx-helpers/v3/pkg/gitclient/giturl" - "github.com/jenkins-x/jx-helpers/v3/pkg/kube" "github.com/jenkins-x/jx-helpers/v3/pkg/kube/activities" appsv1 "k8s.io/api/apps/v1" k8s_v1 "k8s.io/api/core/v1" @@ -81,7 +80,7 @@ func TestCreateOrUpdateActivities(t *testing.T) { ingressConfig := &k8s_v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: kube.ConfigMapIngressConfig, + Name: "ingress-config", }, Data: map[string]string{"key1": "value1", "domain": "test-domain", "config.yml": ""}, } @@ -89,7 +88,7 @@ func TestCreateOrUpdateActivities(t *testing.T) { mockKubeClient.CoreV1().ConfigMaps(nsObj.Namespace).Create(context.TODO(), ingressConfig, metav1.CreateOptions{}) mockTektonDeployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: kube.DeploymentTektonController, + Name: "tekton-pipelines-controller", }, } mockKubeClient.AppsV1().Deployments(nsObj.Namespace).Create(context.TODO(), mockTektonDeployment, metav1.CreateOptions{}) diff --git a/pkg/kube/constants.go b/pkg/kube/constants.go index 4c79eb4..eac3556 100644 --- a/pkg/kube/constants.go +++ b/pkg/kube/constants.go @@ -1,254 +1,21 @@ package kube const ( - // DefaultChartMuseumURL default URL for Jenkins X Charts - DefaultChartMuseumURL = "https://storage.googleapis.com/chartmuseum.jenkins-x.io" - // DefaultChartMuseumJxRepoName default repo name for Jenkins X Charts - DefaultChartMuseumJxRepoName = "jenkins-x" - - // ChartAmbassador the default chart for ambassador - ChartAmbassador = "datawire/ambassador" - - // ChartAnchore the default chart for the Anchore plugin - ChartAnchore = "stable/anchore-engine" - - // ChartExposecontrollerService the default name of the Exposecontroller Service chart for Edit environments - ChartExposecontrollerService = "jenkins-x/exposecontroller-service" - - // ChartAnchore the default chart for the Anchore plugin - ChartPipelineEvent = "jenkins-x/pipeline-events-addon" - - // ChartGitea the default name of the gitea chart - ChartGitea = "jenkins-x/gitea" - - // ChartFlagger the default chart for the Flagger chart - ChartFlagger = "flagger/flagger" - ChartFlaggerGrafana = "flagger/grafana" - DefaultFlaggerReleaseName = "flagger" - - // ChartIstio the default chart for the Istio chart - ChartIstio = "install/kubernetes/helm/istio" - - // ChartKubeless the default chart for kubeless - ChartKubeless = "incubator/kubeless" - - // ChartProw the default chart for Prow - ChartProw = "jenkins-x/prow" - - // ChartKnative the default chart for knative - ChartKnativeBuild = "jenkins-x/knative-build" - - // ChartBuildTemplates the build templates for Knative Build - ChartBuildTemplates = "jenkins-x/jx-build-templates" - - // ChartTekton the default chart for tekton - ChartTekton = "jenkins-x/tekton" - - // DefaultProwReleaseName the default helm release name for Prow - DefaultProwReleaseName = "jx-prow" - - // DefaultKnativeBuildReleaseName the default helm release name for knative build - DefaultKnativeBuildReleaseName = "knative-build" - - // DefaultTektonReleaseName the default helm release name for tekton - DefaultTektonReleaseName = "tekton" - - // DefaultBuildTemplatesReleaseName the default helm release name for the knative build templates - DefaultBuildTemplatesReleaseName = "jx-build-templates" - - // Charts Single Sign-On addon - ChartSsoOperator = "jenkins-x/sso-operator" - DefaultSsoOperatorReleaseName = "jx-sso-operator" - ChartSsoDex = "jenkins-x/dex" - DefaultSsoDexReleaseName = "jx-sso-dex" - - // ChartVaultOperator the default chart for vault opeator - ChartVaultOperator = "jenkins-x/vault-operator" - DefaultVaultOperatorReleaseName = "vault-operator" - - //ChartExternalDNS the default chart for external-dns - ChartOwnerExternalDNS = "bitnami" - ChartURLExternalDNS = "https://charts.bitnami.com/bitnami" - ChartExternalDNS = "bitnami/external-dns" - DefaultExternalDNSReleaseName = "external-dns" - DefaultExternalDNSTag = "1.5.2" - - // SecretKaniko the name of the secret containing the kaniko service account - SecretKaniko = "kaniko-secret" - - // SecretVelero the name of the secret containing the velero service account - SecretVelero = "velero-secret" // #nosec - // ServiceJenkins is the name of the Jenkins Service ServiceJenkins = "jenkins" - // SecretJenkins is the name of the Jenkins secret - SecretJenkins = "jenkins" - // ServiceChartMuseum the service name of the Helm ChartMuseum service ServiceChartMuseum = "jenkins-x-chartmuseum" - // ServiceKubernetesDashboard the Kubernetes dashboard - ServiceKubernetesDashboard = "jenkins-x-kubernetes-dashboard" - // SecretJenkinsChartMuseum the chart museum secret SecretJenkinsChartMuseum = "jenkins-x-chartmuseum" // SecretBucketRepo the bucket repo secret if using it as a chart repositoru SecretBucketRepo = "jenkins-x-bucketrepo" - // SecretJenkinsReleaseGPG the GPG secrets for doing releases - SecretJenkinsReleaseGPG = "jenkins-release-gpg" - - // SecretJenkinsPipelinePrefix prefix for a jenkins pipeline secret name - SecretJenkinsPipelinePrefix = "jx-pipeline-" - - // SecretJenkinsPipelineAddonCredentials the chat credentials secret - SecretJenkinsPipelineAddonCredentials = "jx-pipeline-addon-" // #nosec - - // SecretJenkinsPipelineChatCredentials the chat credentials secret - SecretJenkinsPipelineChatCredentials = "jx-pipeline-chat-" - - // SecretJenkinsPipelineGitCredentials the git credentials secret - SecretJenkinsPipelineGitCredentials = "jx-pipeline-git-" // #nosec - - // SecretJenkinsPipelineIssueCredentials the issue tracker credentials secret - SecretJenkinsPipelineIssueCredentials = "jx-pipeline-issues-" // #nosec - - // ConfigMapExposecontroller the name of the ConfigMap with the Exposecontroller configuration - ConfigMapExposecontroller = "exposecontroller" - - // ConfigMapIngressConfig the new name of the ConfigMap with the Exposecontroller configuration - ConfigMapIngressConfig = "ingress-config" - - // ConfigMapJenkinsX the name of the ConfigMap with the Jenkins configuration - ConfigMapJenkinsX = "jenkins" - - // ConfigMapJenkinsPodTemplates is the ConfigMap containing all the Pod Templates available - ConfigMapJenkinsPodTemplates = "jenkins-x-pod-templates" - - // ConfigMapJenkinsTeamController is the ConfigMap containing the TeamController config files - ConfigMapJenkinsTeamController = "jenkins-x-team-controller" - - // ConfigMapJenkinsDockerRegistry is the ConfigMap containing the Docker Registry configuration - ConfigMapJenkinsDockerRegistry = "jenkins-x-docker-registry" - - // ConfigMapNameJXInstallConfig is the ConfigMap containing the jx installation's CA and server url. Used by jx login - ConfigMapNameJXInstallConfig = "jx-install-config" - // LocalHelmRepoName is the default name of the local chart repository where CI/CD releases go to LocalHelmRepoName = "releases" - // DeploymentTektonController the name of the Deployment for the Tekton Pipeline controller - DeploymentTektonController = "tekton-pipelines-controller" - - // DeploymentExposecontrollerService the name of the Deployment for the Exposecontroller Service - DeploymentExposecontrollerService = "exposecontroller-service" - - // DeploymentProwBuild the name of the Deployment for the Prow webhook engine - DeploymentProwBuild = "prow-build" - - // DefaultGitHubEnvironmentGitRepoURL the default git repository if not using kubnernetes - DefaultGitHubEnvironmentGitRepoURL = "https://github.com/jx3-gitops-repositories/jx3-github.git" - - // DefaultEnvironmentGitRepoURL the default git repository used for environments when using helm 2 - DefaultEnvironmentGitRepoURL = "https://github.com/jenkins-x/default-environment-charts.git" - - // DefaultEnvironmentHelmfileGitRepoURL the default git repository used for remote environments with helmfile - DefaultEnvironmentHelmfileGitRepoURL = "https://github.com/jenkins-x/default-environment-helmfile.git" - - // DefaultEnvironmentHelmfileLocalGitRepoURL the default git repository used for local environments with helmfile - DefaultEnvironmentHelmfileLocalGitRepoURL = "https://github.com/jenkins-x/default-environment-helmfile-local.git" - - DefaultOrganisationGitRepoURL = "https://github.com/jenkins-x/default-organisation.git" - - // AnnotationTitle the human readable name of a resource which can include mixed case, spaces and punctuation - AnnotationTitle = "title" - - // AnnotationDescription the tooltip / texual description of an resource - AnnotationDescription = "description" - - // LabelGitSync to indicate whether or not to sync this resource to GitOps - LabelGitSync = "jenkins.io/gitSync" - - // LabelKind to indicate the kind of auth, such as Git or Issue - LabelKind = "jenkins.io/kind" - - // ValueKindAddon an addon auth secret/credentials - ValueKindAddon = "addon" - - // ValueKindChat a chat auth secret/credentials - ValueKindChat = "chat" - - // ValueKindCVE an CVS App secret/credentials - ValueKindCVE = "cve" - - // ValueKindEnvironmentRole to indicate a Role which maps to an EnvironmentRoleBinding - ValueKindEnvironmentRole = "EnvironmentRole" - - // ValueKindGit a git auth secret/credentials - ValueKindGit = "git" - - // ValueKindIssue an issue auth secret/credentials - ValueKindIssue = "issue" - - // ValueKindChartmuseum a chartmuseum auth secret/credentials - ValueKindChartmuseum = "chartmuseum" - - // ValueKindJenkins an Jenkins App secret/credentials - ValueKindJenkins = "jenkins" - - // ValueKindCVE an addon auth PipelineEvent - ValueKindPipelineEvent = "PipelineEvent" - - // ValueKindPodTemplate a PodTemplate in a ConfigMap - ValueKindPodTemplate = "podTemplate" - - // ValueKindPodTemplateXML a PodTemplate XML in a ConfigMap - ValueKindPodTemplateXML = "podTemplateXml" - - // ValueKindCVE an addon auth PipelineEvent - ValueKindRelease = "Release" - - // ValueKindEditNamespace for edit namespace - ValueKindEditNamespace = "editspace" - - // LabelServiceKind the label to indicate the auto Server's Kind - LabelServiceKind = "jenkins.io/service-kind" - - // LabelGithubAppOwner the label to indicate the owner of a repository for github app token secrets - LabelGithubAppOwner = "jenkins.io/githubapp-owner" - - // LabelCreatedBy indicates the service that created this resource - LabelCreatedBy = "jenkins.io/created-by" - - // LabelPodTemplate the name of the pod template for a DevPod - LabelPodTemplate = "jenkins.io/pod_template" - - // LabelDevPodName the name of a dev pod - LabelDevPodName = "jenkins.io/devpod" - - // LabelDevPodUsername the user name owner of the DeVPod - LabelDevPodUsername = "jenkins.io/devpod_user" - - // LabelDevPodGitPrefix used to label a devpod with the repository host, owner, repo - LabelDevPodGitPrefix = "jenkins.io/repo" - - // LabelUsername the user name owner of a namespace or resource - LabelUsername = "jenkins.io/user" - - // ValueCreatedByJX for resources created by the Jenkins X CLI - ValueCreatedByJX = "jx" - - // LabelCredentialsType the kind of jenkins credential for a secret - LabelCredentialsType = "jenkins.io/credentials-type" - - // ValueCredentialTypeUsernamePassword for user password credential secrets - ValueCredentialTypeUsernamePassword = "usernamePassword" - - // ValueCredentialTypeSecretFile for secret files - ValueCredentialTypeSecretFile = "secretFile" - // LabelTeam indicates the team name an environment belongs to LabelTeam = "team" @@ -258,92 +25,9 @@ const ( // LabelValueDevEnvironment is the value of the LabelTeam label for Development environments (system namespace) LabelValueDevEnvironment = "dev" - // LabelValueThisEnvironment is the value of the LabelTeam label for the current environment in remote clusters - LabelValueThisEnvironment = "this" - - // LabelJobKind the kind of job - LabelJobKind = "jenkins.io/job-kind" - - // ValueJobKindPostPreview - ValueJobKindPostPreview = "post-preview-step" - - // AnnotationURL indicates a service/server's URL - AnnotationURL = "jenkins.io/url" - - // AnnotationExpose used to expose service using exposecontroller - AnnotationExpose = "fabric8.io/expose" - - // AnnotationIngress tells exposecontroller to annotate generated ingress rule with values - AnnotationIngress = "fabric8.io/ingress.annotations" - - // AnnotationExposePort indicates to the exposecontroller which service port to expose - //in case a service has multiple prots - AnnotationExposePort = "fabric8.io/exposePort" - - // AnnotationName indicates a service/server's textual name (can be mixed case, contain spaces unlike Kubernetes resources) - AnnotationName = "jenkins.io/name" - - // AnnotationCredentialsDescription the description text for a Credential on a Secret - AnnotationCredentialsDescription = "jenkins.io/credentials-description" - - // AnnotationWorkingDir the working directory, such as for a DevPod - AnnotationWorkingDir = "jenkins.io/working-dir" - // AnnotationLocalDir the local directory that is sync'd to the DevPod - AnnotationLocalDir = "jenkins.io/local-dir" - // AnnotationGitURLs the newline separated list of git URLs of the DevPods - AnnotationGitURLs = "jenkins.io/git-urls" - // AnnotationGitReportState used to annotate what state has been reported to git - AnnotationGitReportState = "jenkins.io/git-report-state" - // AnnotationGitReportRunningStages used to annotate what stages were last reported to git as running - AnnotationGitReportRunningStages = "jenkins.io/git-report-running-stages" - - // AnnotationIsDefaultStorageClass used to indicate a storageclass is default - AnnotationIsDefaultStorageClass = "storageclass.kubernetes.io/is-default-class" - - // AnnotationReleaseName is the name of the annotation that stores the release name in the preview environment - AnnotationReleaseName = "jenkins.io/chart-release" - // AnnotationHost used to indicate the host if using NodePort Ingress resources on premise without a LoadBalancer AnnotationHost = "jenkins.io/host" - // SecretDataUsername the username in a Secret/Credentials - SecretDataUsername = "username" - - // SecretDataPassword the password in a Secret/Credentials - SecretDataPassword = "password" - // SecretBasicAuth the name for the Jenkins X basic auth secret SecretBasicAuth = "jx-basic-auth" // #nosec - - // JenkinsAdminApiToken the API token - JenkinsAdminApiToken = "jenkins-admin-api-token" - - // JenkinsAdminUserField the admin user name - JenkinsAdminUserField = "jenkins-admin-user" - - // JenkinsAdminPasswordField the password field - JenkinsAdminPasswordField = "jenkins-admin-password" - - // JenkinsBearTokenField the bearer token - JenkinsBearTokenField = "jenkins-bearer-token" - - AUTH = "auth" - - // Region stores the cloud region the cluster is installed on - Region = "region" - - // Zone stores the cloud zone of the install - Zone = "zone" - - // ProjectID stores the project ID used to install the cluster (a GKE thing mostly) - ProjectID = "projectID" - - // ClusterName stores the name of the cluster that is created - ClusterName = "clusterName" - - // KubeProvider stores the kubernetes provider name - KubeProvider = "kubeProvider" - - // SystemVaultName stores the name of the system Vault created on install - SystemVaultName = "systemVaultName" ) diff --git a/pkg/kube/jxclient/jxclient.go b/pkg/kube/jxclient/jxclient.go index 8ba9a1f..fb18277 100644 --- a/pkg/kube/jxclient/jxclient.go +++ b/pkg/kube/jxclient/jxclient.go @@ -74,7 +74,7 @@ func noKubernetesFakeJXClient() (versioned.Interface, error) { ns := "jx" gitURL := os.Getenv("JX_ENVIRONMENT_GIT_URL") if gitURL == "" { - gitURL = kube.DefaultGitHubEnvironmentGitRepoURL + gitURL = "https://github.com/jx3-gitops-repositories/jx3-github.git" } devEnv := jxenv.CreateDefaultDevEnvironment(ns) devEnv.Namespace = ns diff --git a/pkg/kube/jxenv/env.go b/pkg/kube/jxenv/env.go index 4c997bf..0f4a213 100644 --- a/pkg/kube/jxenv/env.go +++ b/pkg/kube/jxenv/env.go @@ -344,15 +344,6 @@ func GetDevEnvironment(jxClient versioned.Interface, ns string) (*v1.Environment ns, name, selector, len(envList.Items), envList.Items) } -// GetPreviewEnvironmentReleaseName returns the (helm) release name for the given (preview) environment -// or the empty string is the environment is not a preview environment, or has no release name associated with it -func GetPreviewEnvironmentReleaseName(env *v1.Environment) string { - if !IsPreviewEnvironment(env) { - return "" - } - return env.Annotations[kube.AnnotationReleaseName] -} - // IsPermanentEnvironment indicates if an environment is permanent func IsPermanentEnvironment(env *v1.Environment) bool { return env.Spec.Kind == v1.EnvironmentKindTypePermanent diff --git a/pkg/kube/jxenv/env_test.go b/pkg/kube/jxenv/env_test.go index 713b64d..4d7489b 100644 --- a/pkg/kube/jxenv/env_test.go +++ b/pkg/kube/jxenv/env_test.go @@ -9,7 +9,6 @@ import ( "github.com/AlecAivazis/survey/v2/core" jenkinsio_v1 "github.com/jenkins-x/jx-api/v4/pkg/apis/jenkins.io/v1" v1 "github.com/jenkins-x/jx-api/v4/pkg/apis/jenkins.io/v1" - "github.com/jenkins-x/jx-helpers/v3/pkg/kube" "github.com/jenkins-x/jx-helpers/v3/pkg/kube/jxenv" "github.com/stretchr/testify/assert" k8sv1 "k8s.io/api/core/v1" @@ -120,46 +119,6 @@ func TestGetDevNamespace(t *testing.T) { assert.Equal(t, testEnv, env) } -func TestGetPreviewEnvironmentReleaseName(t *testing.T) { - t.Parallel() - - tests := []struct { - env *jenkinsio_v1.Environment - expectedReleaseName string - }{ - { - env: nil, - expectedReleaseName: "", - }, - { - env: &jenkinsio_v1.Environment{}, - expectedReleaseName: "", - }, - { - env: jxenv.NewPreviewEnvironment("test"), - expectedReleaseName: "", - }, - { - env: func() *jenkinsio_v1.Environment { - env := jxenv.NewPreviewEnvironment("test") - if env.Annotations == nil { - env.Annotations = map[string]string{} - } - env.Annotations[kube.AnnotationReleaseName] = "release-name" - return env - }(), - expectedReleaseName: "release-name", - }, - } - - for i, test := range tests { - releaseName := jxenv.GetPreviewEnvironmentReleaseName(test.env) - if releaseName != test.expectedReleaseName { - t.Errorf("[%d] Expected release name %s but got %s", i, test.expectedReleaseName, releaseName) - } - } -} - func TestGetRepositoryGitURL(t *testing.T) { tests := []struct { diff --git a/pkg/kube/jxenv/namespaces.go b/pkg/kube/jxenv/namespaces.go index 8ded201..7e0efd0 100644 --- a/pkg/kube/jxenv/namespaces.go +++ b/pkg/kube/jxenv/namespaces.go @@ -7,37 +7,12 @@ import ( v1 "github.com/jenkins-x/jx-api/v4/pkg/apis/jenkins.io/v1" "github.com/jenkins-x/jx-api/v4/pkg/client/clientset/versioned" "github.com/jenkins-x/jx-helpers/v3/pkg/kube" - "github.com/jenkins-x/jx-helpers/v3/pkg/kube/naming" "github.com/jenkins-x/jx-logging/v3/pkg/log" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) -func EnsureEnvironmentNamespaceSetup(kubeClient kubernetes.Interface, jxClient versioned.Interface, env *v1.Environment, ns string) error { - // lets create the namespace if we are on the same cluster - spec := &env.Spec - if spec.Cluster == "" && spec.Namespace != "" { - labels := map[string]string{ - kube.LabelTeam: ns, - kube.LabelEnvironment: env.Name, - } - annotations := map[string]string{} - - err := EnsureNamespaceCreated(kubeClient, spec.Namespace, labels, annotations) - if err != nil { - return err - } - } - - err := EnsureDevNamespaceCreatedWithoutEnvironment(kubeClient, ns) - if err != nil { - return err - } - _, err = EnsureDevEnvironmentSetup(jxClient, ns) - return err -} - // EnsureDevNamespaceCreatedWithoutEnvironment ensures that there is a development namespace created func EnsureDevNamespaceCreatedWithoutEnvironment(kubeClient kubernetes.Interface, ns string) error { // lets annotate the team namespace as being the developer environment @@ -78,11 +53,7 @@ func CreateDefaultDevEnvironment(ns string) *v1.Environment { Label: "Development", PromotionStrategy: v1.PromotionStrategyTypeNever, Kind: v1.EnvironmentKindTypeDevelopment, - TeamSettings: v1.TeamSettings{ - PromotionEngine: "Prow", - AppsRepository: kube.DefaultChartMuseumURL, - }, - WebHookEngine: v1.WebHookEngineLighthouse, + WebHookEngine: v1.WebHookEngineLighthouse, }, } } @@ -100,86 +71,6 @@ func GetEnrichedDevEnvironment(kubeClient kubernetes.Interface, jxClient version return env, nil } -// EnsureEditEnvironmentSetup ensures that the Environment is created in the given namespace -func EnsureEditEnvironmentSetup(kubeClient kubernetes.Interface, jxClient versioned.Interface, ns string, username string) (*v1.Environment, error) { - // lets ensure there is a dev Environment setup so that we can easily switch between all the environments - envList, err := jxClient.JenkinsV1().Environments(ns).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return nil, err - } - if envList != nil { - for _, e := range envList.Items { - if e.Spec.Kind == v1.EnvironmentKindTypeEdit && e.Spec.PreviewGitSpec.User.Username == username { - return &e, nil - } - } - } - - editNS := naming.ToValidName(ns + "-edit-" + username) - labels := map[string]string{ - kube.LabelTeam: ns, - kube.LabelEnvironment: username, - kube.LabelKind: kube.ValueKindEditNamespace, - kube.LabelUsername: username, - } - annotations := map[string]string{} - - err = EnsureNamespaceCreated(kubeClient, editNS, labels, annotations) - if err != nil { - return nil, err - } - - cm, err := kubeClient.CoreV1().ConfigMaps(ns).Get(context.TODO(), kube.ConfigMapIngressConfig, metav1.GetOptions{}) - if err != nil { - cm, err := kubeClient.CoreV1().ConfigMaps(ns).Get(context.TODO(), kube.ConfigMapExposecontroller, metav1.GetOptions{}) - if err != nil { - return nil, err - } - oldCm, err := kubeClient.CoreV1().ConfigMaps(editNS).Get(context.TODO(), kube.ConfigMapExposecontroller, metav1.GetOptions{}) - if oldCm == nil || err != nil { - cm.Namespace = editNS - cm.ResourceVersion = "" - _, err := kubeClient.CoreV1().ConfigMaps(editNS).Create(context.TODO(), cm, metav1.CreateOptions{}) - if err != nil { - return nil, err - } - } - } else { - oldCm, err := kubeClient.CoreV1().ConfigMaps(editNS).Get(context.TODO(), kube.ConfigMapIngressConfig, metav1.GetOptions{}) - if oldCm == nil || err != nil { - cm.Namespace = editNS - cm.ResourceVersion = "" - _, err := kubeClient.CoreV1().ConfigMaps(editNS).Create(context.TODO(), cm, metav1.CreateOptions{}) - if err != nil { - return nil, err - } - } - } - - env := &v1.Environment{ - ObjectMeta: metav1.ObjectMeta{ - Name: username, - }, - Spec: v1.EnvironmentSpec{ - Namespace: editNS, - Label: username, - PromotionStrategy: v1.PromotionStrategyTypeNever, - Kind: v1.EnvironmentKindTypeEdit, - PreviewGitSpec: v1.PreviewGitSpec{ - User: v1.UserSpec{ - Username: username, - }, - }, - Order: 1, - }, - } - _, err = jxClient.JenkinsV1().Environments(ns).Create(context.TODO(), env, metav1.CreateOptions{}) - if err != nil { - return nil, err - } - return env, nil -} - // Ensure that the namespace exists for the given name func EnsureNamespaceCreated(kubeClient kubernetes.Interface, name string, labels map[string]string, annotations map[string]string) error { n, err := kubeClient.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{}) diff --git a/pkg/kube/jxenv/namespaces_test.go b/pkg/kube/jxenv/namespaces_test.go index 136305f..5afe944 100644 --- a/pkg/kube/jxenv/namespaces_test.go +++ b/pkg/kube/jxenv/namespaces_test.go @@ -28,9 +28,6 @@ func TestEnsureDevEnvironmentSetup(t *testing.T) { Label: "Development", PromotionStrategy: jenkinsio_v1.PromotionStrategyTypeNever, Kind: jenkinsio_v1.EnvironmentKindTypeDevelopment, - TeamSettings: jenkinsio_v1.TeamSettings{ - AppsRepository: kube.DefaultChartMuseumURL, - }, }, } @@ -42,6 +39,4 @@ func TestEnsureDevEnvironmentSetup(t *testing.T) { assert.Equal(t, envFixture.Spec.Label, env.Spec.Label) assert.Equal(t, jenkinsio_v1.PromotionStrategyType("Never"), env.Spec.PromotionStrategy) assert.Equal(t, jenkinsio_v1.EnvironmentKindType("Development"), env.Spec.Kind) - assert.Equal(t, jenkinsio_v1.PromotionEngineType("Prow"), env.Spec.TeamSettings.PromotionEngine) - assert.Equal(t, envFixture.Spec.TeamSettings.AppsRepository, env.Spec.TeamSettings.AppsRepository) } diff --git a/pkg/kube/naming/names.go b/pkg/kube/naming/names.go index 6c03920..254ab46 100644 --- a/pkg/kube/naming/names.go +++ b/pkg/kube/naming/names.go @@ -7,7 +7,7 @@ import ( "strings" "unicode" - uuid "github.com/google/uuid" + "github.com/google/uuid" ) // ToValidImageName converts the given string into a valid docker image name diff --git a/pkg/kube/services/services.go b/pkg/kube/services/services.go index 65e2322..4c67ec0 100644 --- a/pkg/kube/services/services.go +++ b/pkg/kube/services/services.go @@ -4,40 +4,24 @@ import ( "context" "errors" "fmt" - "sort" - "strconv" - "strings" - "time" - "github.com/jenkins-x/jx-helpers/v3/pkg/kube" "github.com/jenkins-x/jx-helpers/v3/pkg/stringhelpers" "github.com/jenkins-x/jx-logging/v3/pkg/log" + "sort" + "strconv" + "strings" v1 "k8s.io/api/core/v1" nv1 "k8s.io/api/networking/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" - tools_watch "k8s.io/client-go/tools/watch" ) -const ( - ExposeAnnotation = "fabric8.io/expose" - ExposeURLAnnotation = "fabric8.io/exposeUrl" - ExposeGeneratedByAnnotation = "fabric8.io/generated-by" - ExposeIngressName = "fabric8.io/ingress.name" - JenkinsXSkipTLSAnnotation = "jenkins-x.io/skip.tls" - ExposeIngressAnnotation = "fabric8.io/ingress.annotations" - CertManagerAnnotation = "certmanager.k8s.io/issuer" - CertManagerClusterAnnotation = "certmanager.k8s.io/cluster-issuer" - ServiceAppLabel = "app" -) +const ExposeURLAnnotation = "fabric8.io/exposeUrl" type ServiceURL struct { Name string @@ -381,57 +365,6 @@ func FindServiceURLs(client kubernetes.Interface, namespace string) ([]ServiceUR return urls, nil } -// WaitForExternalIP waits for the pods of a deployment to become ready -func WaitForExternalIP(client kubernetes.Interface, name, namespace string, timeout time.Duration) error { - options := meta_v1.ListOptions{ - FieldSelector: fields.OneTermEqualSelector("metadata.name", name).String(), - } - - w, err := client.CoreV1().Services(namespace).Watch(context.TODO(), options) - if err != nil { - return err - } - defer w.Stop() - - condition := func(event watch.Event) (bool, error) { - svc := event.Object.(*v1.Service) - return HasExternalAddress(svc), nil - } - - ctx, _ := context.WithTimeout(context.Background(), timeout) - _, err = tools_watch.UntilWithoutRetry(ctx, w, condition) - - if err == wait.ErrWaitTimeout { - return fmt.Errorf("service %s never became ready", name) - } - return nil -} - -// WaitForService waits for a service to become ready -func WaitForService(client kubernetes.Interface, name, namespace string, timeout time.Duration) error { - options := meta_v1.ListOptions{ - FieldSelector: fields.OneTermEqualSelector("metadata.name", name).String(), - } - w, err := client.CoreV1().Services(namespace).Watch(context.TODO(), options) - if err != nil { - return err - } - defer w.Stop() - - condition := func(event watch.Event) (bool, error) { - svc := event.Object.(*v1.Service) - return svc.GetName() == name, nil - } - ctx, _ := context.WithTimeout(context.Background(), timeout) - _, err = tools_watch.UntilWithoutRetry(ctx, w, condition) - - if err == wait.ErrWaitTimeout { - return fmt.Errorf("service %s never became ready", name) - } - - return nil -} - func HasExternalAddress(svc *v1.Service) bool { for _, v := range svc.Status.LoadBalancer.Ingress { if v.IP != "" || v.Hostname != "" { @@ -441,34 +374,6 @@ func HasExternalAddress(svc *v1.Service) bool { return false } -func CreateServiceLink(client kubernetes.Interface, currentNamespace, targetNamespace, serviceName, externalURL string) error { - annotations := make(map[string]string) - annotations[ExposeURLAnnotation] = externalURL - - svc := v1.Service{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: serviceName, - Namespace: currentNamespace, - Annotations: annotations, - }, - Spec: v1.ServiceSpec{ - Type: v1.ServiceTypeExternalName, - ExternalName: fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, targetNamespace), - }, - } - - _, err := client.CoreV1().Services(currentNamespace).Create(context.TODO(), &svc, meta_v1.CreateOptions{}) - if err != nil { - return err - } - - return nil -} - -func DeleteService(client *kubernetes.Clientset, namespace string, serviceName string) error { - return client.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, meta_v1.DeleteOptions{}) -} - func GetService(client kubernetes.Interface, currentNamespace, targetNamespace, serviceName string) error { svc := v1.Service{ ObjectMeta: meta_v1.ObjectMeta{ @@ -487,167 +392,6 @@ func GetService(client kubernetes.Interface, currentNamespace, targetNamespace, return nil } -func IsServicePresent(c kubernetes.Interface, name, ns string) (bool, error) { - svc, err := c.CoreV1().Services(ns).Get(context.TODO(), name, meta_v1.GetOptions{}) - if err != nil || svc == nil { - return false, err - } - return true, nil -} - -// GetServiceAppName retrieves the application name from the service labels -func GetServiceAppName(c kubernetes.Interface, name, ns string) (string, error) { - svc, err := c.CoreV1().Services(ns).Get(context.TODO(), name, meta_v1.GetOptions{}) - if err != nil || svc == nil { - return "", fmt.Errorf("retrieving service %q: %w", name, err) - } - return ServiceAppName(svc), nil -} - -// ServiceAppName retrives the application name from service labels. If no app lable exists, -// it returns the service name -func ServiceAppName(service *v1.Service) string { - if annotations := service.Annotations; annotations != nil { - ingName, ok := annotations[ExposeIngressName] - if ok { - return ingName - } - } - if labels := service.Labels; labels != nil { - app, ok := labels[ServiceAppLabel] - if ok { - return app - } - } - return service.GetName() -} - -// AnnotateServicesWithCertManagerIssuer adds the cert-manager annotation to the services from the given namespace. If a list of -// services is provided, it will apply the annotation only to that specific services. -func AnnotateServicesWithCertManagerIssuer(c kubernetes.Interface, ns, issuer string, clusterIssuer bool, services ...string) ([]*v1.Service, error) { - result := make([]*v1.Service, 0) - svcList, err := GetServices(c, ns) - if err != nil { - return result, err - } - - for _, s := range svcList { - // annotate only the services present in the list, if the list is empty annotate all services - if len(services) > 0 { - i := stringhelpers.StringArrayIndex(services, s.GetName()) - if i < 0 { - continue - } - } - if s.Annotations[ExposeAnnotation] == "true" && s.Annotations[JenkinsXSkipTLSAnnotation] != "true" { - existingAnnotations, _ := s.Annotations[ExposeIngressAnnotation] - // if no existing `fabric8.io/ingress.annotations` initialise and add else update with ClusterIssuer - certManagerAnnotation := CertManagerAnnotation - if clusterIssuer == true { - certManagerAnnotation = CertManagerClusterAnnotation - } - if len(existingAnnotations) > 0 { - s.Annotations[ExposeIngressAnnotation] = existingAnnotations + "\n" + certManagerAnnotation + ": " + issuer - } else { - s.Annotations[ExposeIngressAnnotation] = certManagerAnnotation + ": " + issuer - } - s, err = c.CoreV1().Services(ns).Update(context.TODO(), s, meta_v1.UpdateOptions{}) - if err != nil { - return result, fmt.Errorf("failed to annotate and update service %s in namespace %s: %v", s.Name, ns, err) - } - result = append(result, s) - } - } - return result, nil -} - -// AnnotateServicesWithBasicAuth annotates the services with nginx baisc auth annotations -func AnnotateServicesWithBasicAuth(client kubernetes.Interface, ns string, services ...string) error { - if len(services) == 0 { - return nil - } - svcList, err := GetServices(client, ns) - if err != nil { - return fmt.Errorf("retrieving the services from namespace %q: %w", ns, err) - } - for _, service := range svcList { - // Check if the service is in the white-list - idx := stringhelpers.StringArrayIndex(services, service.GetName()) - if idx < 0 { - continue - } - if service.Annotations == nil { - service.Annotations = map[string]string{} - } - // Add the required basic authentication annotation for nginx-ingress controller - ingressAnnotations := service.Annotations[ExposeIngressAnnotation] - basicAuthAnnotations := fmt.Sprintf( - "nginx.ingress.kubernetes.io/auth-type: basic\nnginx.ingress.kubernetes.io/auth-secret: %s\nnginx.ingress.kubernetes.io/auth-realm: Authentication is required to access this service", - kube.SecretBasicAuth) - if ingressAnnotations != "" { - ingressAnnotations = ingressAnnotations + "\n" + basicAuthAnnotations - } else { - ingressAnnotations = basicAuthAnnotations - } - service.Annotations[ExposeIngressAnnotation] = ingressAnnotations - _, err = client.CoreV1().Services(ns).Update(context.TODO(), service, meta_v1.UpdateOptions{}) - if err != nil { - return fmt.Errorf("updating the service %q in namesapce %q: %w", service.GetName(), ns, err) - } - } - return nil -} - -func CleanServiceAnnotations(c kubernetes.Interface, ns string, services ...string) error { - svcList, err := GetServices(c, ns) - if err != nil { - return err - } - for _, s := range svcList { - // clear the annotations only for the services provided in the list if the list - // is not empty, otherwise clear the annotations of all services - if len(services) > 0 { - i := stringhelpers.StringArrayIndex(services, s.GetName()) - if i < 0 { - continue - } - } - if s.Annotations[ExposeAnnotation] == "true" && s.Annotations[JenkinsXSkipTLSAnnotation] != "true" { - // if no existing `fabric8.io/ingress.annotations` initialise and add else update with ClusterIssuer - annotationsForIngress := s.Annotations[ExposeIngressAnnotation] - if len(annotationsForIngress) > 0 { - - var newAnnotations []string - annotations := strings.Split(annotationsForIngress, "\n") - for _, element := range annotations { - annotation := strings.SplitN(element, ":", 2) - key, _ := annotation[0], strings.TrimSpace(annotation[1]) - if key != CertManagerAnnotation && key != CertManagerClusterAnnotation { - newAnnotations = append(newAnnotations, element) - } - } - annotationsForIngress = "" - for _, v := range newAnnotations { - if len(annotationsForIngress) > 0 { - annotationsForIngress = annotationsForIngress + "\n" + v - } else { - annotationsForIngress = v - } - } - s.Annotations[ExposeIngressAnnotation] = annotationsForIngress - - } - delete(s.Annotations, ExposeURLAnnotation) - - _, err = c.CoreV1().Services(ns).Update(context.TODO(), s, meta_v1.UpdateOptions{}) - if err != nil { - return fmt.Errorf("failed to clean service %s annotations in namespace %s: %v", s.Name, ns, err) - } - } - } - return nil -} - // ExtractServiceSchemePort is a utility function to interpret http scheme and port information from k8s service definitions func ExtractServiceSchemePort(svc *v1.Service) (string, string, error) { scheme := "" diff --git a/pkg/kyamls/filter.go b/pkg/kyamls/filter.go index 9e399b4..b910c98 100644 --- a/pkg/kyamls/filter.go +++ b/pkg/kyamls/filter.go @@ -113,7 +113,7 @@ func (f *Filter) AddKindFlags(cmd *cobra.Command) { // AddSelectorFlags add CLI flags for specifying the selector part of a filter func (f *Filter) AddSelectorFlags(cmd *cobra.Command) { cmd.Flags().StringToStringVarP(&f.Selector, "selector", "", nil, - "adds Kubernetes label selector to filter on, e.g. --selector app=pusher-wave,heritage=Helm") + "adds Kubernetes label selector to filter on, e.g. --selector app=wave,heritage=Helm") cmd.Flags().StringVar(&f.SelectTarget, "selector-target", "", "sets which path in the Kubernetes resources to select on instead of metadata.labels.") cmd.Flags().BoolVarP(&f.InvertSelector, "invert-selector", "", false,