Skip to content

Commit 960f6b5

Browse files
authored
implement cluster add and list (#288)
added kustomization, fixed helm added kustimized add-cluster to release generate kustomization for add-cluster create and build kustomization added dry-run added helm labels renamed add-cluster to csdp-add-clsuter added add-cluster-script pipeline added runtime version check fixed secret creation, delete secret on success keep the job for 10m after completion add helm release.name to resources added argocd vars to app-proxy deployment renamed pipeline script file added the default argocd username into the configmapGenerator updated version to 0.0.283 deploy app-proxy 1.923.0
1 parent d4cfed1 commit 960f6b5

38 files changed

+1089
-199
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Changelog:
22

3-
* Moved Codefresh ci pipeline into the repo
3+
* Added cluster commands

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION=v0.0.282
1+
VERSION=v0.0.283
22

33
OUT_DIR=dist
44
YEAR?=$(shell date +"%Y")
@@ -8,8 +8,10 @@ IMAGE_REPOSITORY?=quay.io
88
IMAGE_NAMESPACE?=codefresh
99

1010
RUNTIME_DEF_URL="https://github.com/codefresh-io/cli-v2/releases/latest/download/runtime.yaml"
11+
ADD_CLUSTER_DEF_URL="https://github.com/codefresh-io/cli-v2/manifests/add-cluster/kustomize"
1112

1213
DEV_RUNTIME_DEF_URL="manifests/runtime.yaml"
14+
DEV_ADD_CLUSTER_DEF_URL="../manifests/add-cluster/kustomize"
1315

1416
CLI_SRCS := $(shell find . -name '*.go')
1517

@@ -23,6 +25,7 @@ SEGMENT_WRITE_KEY?=""
2325

2426
ifeq (${DEV_MODE},true)
2527
RUNTIME_DEF_URL=${DEV_RUNTIME_DEF_URL}
28+
ADD_CLUSTER_DEF_URL=${DEV_ADD_CLUSTER_DEF_URL}
2629
endif
2730

2831
ifndef GOBIN
@@ -97,6 +100,7 @@ $(OUT_DIR)/$(CLI_NAME)-%: $(CLI_SRCS)
97100
GIT_COMMIT=$(GIT_COMMIT) \
98101
OUT_FILE=$(OUT_DIR)/$(CLI_NAME)-$* \
99102
RUNTIME_DEF_URL=$(RUNTIME_DEF_URL) \
103+
ADD_CLUSTER_DEF_URL=$(ADD_CLUSTER_DEF_URL) \
100104
SEGMENT_WRITE_KEY=$(SEGMENT_WRITE_KEY) \
101105
MAIN=./cmd \
102106
./hack/build.sh

build/add-cluster-script.yaml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
version: '1.0'
2+
mode: parallel
3+
4+
stages:
5+
- Prepare
6+
- Test
7+
- Release
8+
9+
steps:
10+
main_clone:
11+
stage: Prepare
12+
title: clone repository
13+
type: git-clone
14+
git: cf_github
15+
repo: ${{CF_REPO_OWNER}}/${{CF_REPO_NAME}}
16+
revision: ${{CF_BRANCH}}
17+
18+
prepare_env_vars:
19+
stage: Prepare
20+
title: prepare-env
21+
image: codefresh/semver:latest
22+
working_directory: manifests/add-cluster
23+
commands:
24+
- cf_export CHART_VERSION=$(yq ".version" helm/Chart.yaml | tr -d '"')
25+
- cf_export IMAGE_VERSION=$(yq ".appVersion" helm/Chart.yaml | tr -d '"')
26+
when:
27+
steps:
28+
- name: main_clone
29+
on:
30+
- success
31+
32+
compare_versions:
33+
stage: Test
34+
title: Compare versions
35+
image: codefresh/semver:latest
36+
commands:
37+
- hack/compare-versions.sh
38+
when:
39+
steps:
40+
- name: prepare_env_vars
41+
on:
42+
- success
43+
44+
build_image:
45+
stage: Release
46+
type: build
47+
title: build and push add-cluster image
48+
working_directory: manifests/add-cluster
49+
image_name: codefresh/csdp-add-cluster
50+
tag: ${{IMAGE_VERSION}}
51+
tags:
52+
- latest
53+
- ${{IMAGE_VERSION}}
54+
registry: ${{REGISTRY_INTEGRATION_QUAY}}
55+
buildkit: true
56+
when:
57+
steps:
58+
- name: compare_versions
59+
on:
60+
- success
61+
62+
publish_chart:
63+
stage: Release
64+
title: publish helm chart
65+
image: quay.io/codefresh/golang-ci-helper:latest # change it
66+
working_directory: manifests/add-cluster
67+
environment:
68+
- CHART_VERSION=${{CHART_VERSION}}
69+
commands:
70+
- echo "inside publish helm chart ${CHART_VERSION}"
71+
when:
72+
steps:
73+
- name: build_image
74+
on:
75+
- success

cmd/commands/cluster.go

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
// Copyright 2022 The Codefresh Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package commands
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"os"
21+
"strings"
22+
23+
"github.com/codefresh-io/cli-v2/pkg/log"
24+
"github.com/codefresh-io/cli-v2/pkg/store"
25+
"github.com/codefresh-io/cli-v2/pkg/util"
26+
cdutil "github.com/codefresh-io/cli-v2/pkg/util/cd"
27+
kustutil "github.com/codefresh-io/cli-v2/pkg/util/kust"
28+
29+
"github.com/Masterminds/semver/v3"
30+
"github.com/argoproj-labs/argocd-autopilot/pkg/kube"
31+
"github.com/juju/ansiterm"
32+
"github.com/spf13/cobra"
33+
kusttypes "sigs.k8s.io/kustomize/api/types"
34+
)
35+
36+
type (
37+
ClusterAddOptions struct {
38+
runtimeName string
39+
kubeContext string
40+
dryRun bool
41+
kubeFactory kube.Factory
42+
}
43+
)
44+
45+
var minAddClusterSupportedVersion = semver.MustParse("0.0.283")
46+
47+
func NewClusterCommand() *cobra.Command {
48+
cmd := &cobra.Command{
49+
Hidden: true, // until app-proxy is working correctly
50+
Use: "cluster",
51+
Short: "Manage clusters of Codefresh runtimes",
52+
PersistentPreRunE: cfConfig.RequireAuthentication,
53+
Args: cobra.NoArgs, // Workaround for subcommand usage errors. See: https://github.com/spf13/cobra/issues/706
54+
Run: func(cmd *cobra.Command, args []string) {
55+
cmd.HelpFunc()(cmd, args)
56+
exit(1)
57+
},
58+
}
59+
60+
cmd.AddCommand(NewClusterAddCommand())
61+
cmd.AddCommand(NewClusterListCommand())
62+
63+
return cmd
64+
}
65+
66+
func NewClusterAddCommand() *cobra.Command {
67+
var (
68+
opts ClusterAddOptions
69+
err error
70+
)
71+
72+
cmd := &cobra.Command{
73+
Use: "add RUNTIME_NAME",
74+
Short: "Add a cluster to a given runtime",
75+
Args: cobra.MaximumNArgs(1),
76+
Example: util.Doc(`<BIN> cluster add my-runtime --context my-context`),
77+
PreRunE: func(cmd *cobra.Command, args []string) error {
78+
var err error
79+
80+
ctx := cmd.Context()
81+
82+
opts.runtimeName, err = ensureRuntimeName(ctx, args)
83+
if err != nil {
84+
return err
85+
}
86+
87+
opts.kubeContext, err = ensureKubeContextName(cmd.Flag("context"))
88+
return err
89+
},
90+
RunE: func(cmd *cobra.Command, args []string) error {
91+
return runClusterAdd(cmd.Context(), &opts)
92+
},
93+
}
94+
95+
cmd.Flags().BoolVar(&opts.dryRun, "dry-run", false, "")
96+
opts.kubeFactory = kube.AddFlags(cmd.Flags())
97+
die(err)
98+
99+
return cmd
100+
}
101+
102+
func runClusterAdd(ctx context.Context, opts *ClusterAddOptions) error {
103+
runtime, err := cfConfig.NewClient().V2().Runtime().Get(ctx, opts.runtimeName)
104+
if err != nil {
105+
return err
106+
}
107+
108+
if runtime.RuntimeVersion == nil {
109+
return fmt.Errorf("runtime \"%s\" has no version", opts.runtimeName)
110+
}
111+
112+
version := semver.MustParse(*runtime.RuntimeVersion)
113+
if version.LessThan(minAddClusterSupportedVersion) {
114+
return fmt.Errorf("runtime \"%s\" does not support this command. Minimal required version is %s", opts.runtimeName, minAddClusterSupportedVersion)
115+
}
116+
117+
if runtime.IngressHost == nil {
118+
return fmt.Errorf("runtime \"%s\" is missing an ingress URL", opts.runtimeName)
119+
}
120+
121+
ingressUrl := *runtime.IngressHost
122+
server, err := util.KubeServerByContextName(opts.kubeContext)
123+
if err != nil {
124+
return fmt.Errorf("failed getting server for context \"%s\": %w", opts.kubeContext, err)
125+
}
126+
127+
csdpToken := cfConfig.GetCurrentContext().Token
128+
k := createAddClusterKustomization(ingressUrl, opts.kubeContext, server, csdpToken, *runtime.RuntimeVersion)
129+
130+
manifests, err := kustutil.BuildKustomization(k)
131+
if err != nil {
132+
return fmt.Errorf("failed building kustomization:%w", err)
133+
}
134+
135+
if opts.dryRun {
136+
fmt.Println(string(manifests))
137+
return nil
138+
}
139+
140+
return opts.kubeFactory.Apply(ctx, "", manifests)
141+
}
142+
143+
func createAddClusterKustomization(ingressUrl, contextName, server, csdpToken, version string) *kusttypes.Kustomization {
144+
resourceUrl := store.AddClusterDefURL
145+
if strings.HasPrefix(resourceUrl, "http") {
146+
resourceUrl = fmt.Sprintf("%s?ref=%s", resourceUrl, version)
147+
}
148+
149+
k := &kusttypes.Kustomization{
150+
ConfigMapGenerator: []kusttypes.ConfigMapArgs{
151+
{
152+
GeneratorArgs: kusttypes.GeneratorArgs{
153+
Namespace: "kube-system",
154+
Name: "csdp-add-cluster-cm",
155+
Behavior: "merge",
156+
KvPairSources: kusttypes.KvPairSources{
157+
LiteralSources: []string{
158+
fmt.Sprintf("ingressUrl=" + ingressUrl),
159+
fmt.Sprintf("contextName=" + contextName),
160+
fmt.Sprintf("server=" + server),
161+
},
162+
},
163+
},
164+
},
165+
},
166+
SecretGenerator: []kusttypes.SecretArgs{
167+
{
168+
GeneratorArgs: kusttypes.GeneratorArgs{
169+
Namespace: "kube-system",
170+
Name: "csdp-add-cluster-secret",
171+
Behavior: "merge",
172+
KvPairSources: kusttypes.KvPairSources{
173+
LiteralSources: []string{
174+
fmt.Sprintf("csdpToken=" + csdpToken),
175+
},
176+
},
177+
},
178+
},
179+
},
180+
Resources: []string{
181+
resourceUrl,
182+
},
183+
}
184+
k.FixKustomizationPostUnmarshalling()
185+
util.Die(k.FixKustomizationPreMarshalling())
186+
return k
187+
}
188+
189+
func NewClusterListCommand() *cobra.Command {
190+
var runtimeName string
191+
192+
cmd := &cobra.Command{
193+
Use: "list RUNTIME_NAME",
194+
Short: "List all the clusters of a given runtime",
195+
Args: cobra.MaximumNArgs(1),
196+
Example: util.Doc(`<BIN> cluster list my-runtime`),
197+
PreRunE: func(cmd *cobra.Command, args []string) error {
198+
var err error
199+
200+
runtimeName, err = ensureRuntimeName(cmd.Context(), args)
201+
return err
202+
},
203+
RunE: func(cmd *cobra.Command, _ []string) error {
204+
return runClusterList(cmd.Context(), runtimeName)
205+
},
206+
}
207+
208+
return cmd
209+
}
210+
211+
func runClusterList(ctx context.Context, runtimeName string) error {
212+
runtime, err := cfConfig.NewClient().V2().Runtime().Get(ctx, runtimeName)
213+
if err != nil {
214+
return err
215+
}
216+
217+
kubeContext, err := util.KubeContextNameByServer(*runtime.Cluster)
218+
if err != nil {
219+
return fmt.Errorf("failed getting context for \"%s\": %w", *runtime.Cluster, err)
220+
}
221+
222+
clusters, err := cdutil.GetClusterList(ctx, kubeContext, *runtime.Metadata.Namespace, false)
223+
if err != nil {
224+
return err
225+
}
226+
227+
if len(clusters.Items) == 0 {
228+
log.G(ctx).Info("No clusters were found")
229+
return nil
230+
}
231+
232+
tb := ansiterm.NewTabWriter(os.Stdout, 0, 0, 4, ' ', 0)
233+
_, err = fmt.Fprintln(tb, "SERVER\tNAME\tVERSION\tSTATUS\tMESSAGE")
234+
if err != nil {
235+
return err
236+
}
237+
238+
for _, c := range clusters.Items {
239+
server := c.Server
240+
if len(c.Namespaces) > 0 {
241+
server = fmt.Sprintf("%s (%d namespaces)", c.Server, len(c.Namespaces))
242+
}
243+
244+
_, err = fmt.Fprintf(tb, "%s\t%s\t%s\t%s\t%s\n",
245+
server,
246+
c.Name,
247+
c.ServerVersion,
248+
c.ConnectionState.Status,
249+
c.ConnectionState.Message,
250+
)
251+
if err != nil {
252+
return err
253+
}
254+
}
255+
256+
return tb.Flush()
257+
}

0 commit comments

Comments
 (0)