Skip to content

Commit 7e6532c

Browse files
authored
Merge pull request #68 from wunderio/feature/pullsecrets
Add support for custom imagePullSecret and per-cluster env var overrides
2 parents 18d8b07 + 4bf0bfa commit 7e6532c

16 files changed

+393
-25
lines changed

cmd/ciReleaseDeploy.go

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import (
1111

1212
"github.com/spf13/cobra"
1313
"github.com/wunderio/silta-cli/internal/common"
14-
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
v1core "k8s.io/api/core/v1"
15+
v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
1516
"k8s.io/client-go/kubernetes"
1617
"k8s.io/client-go/tools/clientcmd"
1718
)
@@ -25,6 +26,9 @@ var ciReleaseDeployCmd = &cobra.Command{
2526
* Chart allows prepending extra configuration (to helm --values line) via
2627
"SILTA_<chart_name>_CONFIG_VALUES" environment variable. It has to be a
2728
base64 encoded string of a silta configuration yaml file.
29+
30+
* If IMAGE_PULL_SECRET is set (base64 encoded), it will be added to the
31+
release values as imagePullSecret.
2832
`,
2933
Run: func(cmd *cobra.Command, args []string) {
3034

@@ -145,26 +149,43 @@ var ciReleaseDeployCmd = &cobra.Command{
145149
chartVersionOverride = fmt.Sprintf("--version '%s'", chartVersion)
146150
}
147151

148-
// TODO: Create namespace if it doesn't exist
149-
// & tag the namespace if it isn't already tagged.
150-
// TODO: Rewrite
151-
152-
command := fmt.Sprintf(`
153-
# Deployed chart version
154-
NAMESPACE='%s'
152+
if !debug {
153+
// Connect to the cluster
154+
homeDir, err := os.UserHomeDir()
155+
if err != nil {
156+
log.Fatalf("cannot read user home dir")
157+
}
158+
kubeConfigPath := homeDir + "/.kube/config"
155159

156-
# Create the namespace if it doesn't exist.
157-
if ! kubectl get namespace "$NAMESPACE" &>/dev/null ; then
158-
kubectl create namespace "$NAMESPACE"
159-
fi
160+
//k8s go client init logic
161+
config, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath)
162+
if err != nil {
163+
log.Fatalf("cannot read kubeConfig from path: %s", err)
164+
}
165+
clientset, err := kubernetes.NewForConfig(config)
166+
if err != nil {
167+
log.Fatalf("cannot initialize k8s client: %s", err)
168+
}
160169

161-
# Tag the namespace if it isn't already tagged.
162-
if ! kubectl get namespace -l name=$NAMESPACE --no-headers 2>/dev/null | grep $NAMESPACE &>/dev/null ; then
163-
kubectl label namespace "$NAMESPACE" "name=$NAMESPACE" --overwrite
164-
fi
170+
// Create namespace if it doesn't exist
171+
_, err = clientset.CoreV1().Namespaces().Get(context.TODO(), namespace, v1meta.GetOptions{})
172+
if err != nil {
173+
_, err = clientset.CoreV1().Namespaces().Create(context.TODO(), &v1core.Namespace{
174+
ObjectMeta: v1meta.ObjectMeta{
175+
Name: namespace,
176+
},
177+
}, v1meta.CreateOptions{})
178+
if err != nil {
179+
log.Fatalf("cannot create namespace: %s", err)
180+
}
181+
}
182+
}
165183

166-
`, namespace)
167-
pipedExec(command, "", "ERROR: ", debug)
184+
// Add imagePullsecret to release values if IMAGE_PULL_SECRET is set
185+
imagePullSecret := os.Getenv("IMAGE_PULL_SECRET")
186+
if len(imagePullSecret) > 0 {
187+
helmFlags = fmt.Sprintf("%s --set imagePullSecret='%s'", helmFlags, imagePullSecret)
188+
}
168189

169190
if !debug {
170191
// Add helm repositories
@@ -180,6 +201,8 @@ var ciReleaseDeployCmd = &cobra.Command{
180201
exec.Command("bash", "-c", command).Run()
181202
}
182203

204+
command := ""
205+
183206
if chartName == "simple" || strings.HasSuffix(chartName, "/simple") {
184207

185208
if len(nginxImageUrl) == 0 {
@@ -493,6 +516,7 @@ var ciReleaseDeployCmd = &cobra.Command{
493516
referenceDataOverride := ""
494517
if !debug {
495518

519+
// Connect to the cluster
496520
homeDir, err := os.UserHomeDir()
497521
if err != nil {
498522
log.Fatalf("cannot read user home dir")
@@ -512,7 +536,7 @@ var ciReleaseDeployCmd = &cobra.Command{
512536
// PVC name can be either "*-reference-data" or "*-reference", so we need to check both
513537
// Unless we parse and merge configuration yaml files, we can't know the exact name of the PVC
514538
// Check all pvc's in the namespace and see if any of them match the pattern
515-
pvcs, err := clientset.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), v1.ListOptions{})
539+
pvcs, err := clientset.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), v1meta.ListOptions{})
516540
if err != nil {
517541
log.Fatalf("cannot get persistent volume claims: %s", err)
518542
}

cmd/ciReleaseDiff.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ var ciReleaseDiffCmd = &cobra.Command{
2424
* Chart allows prepending extra configuration (to helm --values line) via
2525
"SILTA_<chart_name>_CONFIG_VALUES" environment variable. It has to be a
2626
base64 encoded string of a silta configuration yaml file.
27+
28+
* If IMAGE_PULL_SECRET is set (base64 encoded), it will be added to the
29+
release values as imagePullSecret.
2730
`,
2831
Run: func(cmd *cobra.Command, args []string) {
2932

@@ -131,9 +134,11 @@ var ciReleaseDiffCmd = &cobra.Command{
131134
chartVersionOverride = fmt.Sprintf("--version '%s'", chartVersion)
132135
}
133136

134-
// TODO: Create namespace if it doesn't exist
135-
// & tag the namespace if it isn't already tagged.
136-
// TODO: Rewrite
137+
// Add imagePullsecret to release values if IMAGE_PULL_SECRET is set
138+
imagePullSecret := os.Getenv("IMAGE_PULL_SECRET")
139+
if len(imagePullSecret) > 0 {
140+
helmFlags = fmt.Sprintf("%s --set imagePullSecret='%s'", helmFlags, imagePullSecret)
141+
}
137142

138143
if !debug {
139144
// Add helm repositories

cmd/ciReleaseList.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
helmclient "github.com/mittwald/go-helm-client"
8+
"github.com/spf13/cobra"
9+
"helm.sh/helm/v3/pkg/action"
10+
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // gcp auth provider
11+
12+
"text/tabwriter"
13+
)
14+
15+
var ciReleaseListCmd = &cobra.Command{
16+
Use: "list",
17+
Short: "List releases",
18+
Run: func(cmd *cobra.Command, args []string) {
19+
20+
namespace, _ := cmd.Flags().GetString("namespace")
21+
22+
homeDir, err := os.UserHomeDir()
23+
if err != nil {
24+
fmt.Println("cannot read user home dir")
25+
os.Exit(1)
26+
}
27+
kubeConfigPath := homeDir + "/.kube/config"
28+
29+
kubeConfig, err := os.ReadFile(kubeConfigPath)
30+
if err != nil {
31+
fmt.Println("cannot read kubeConfig from path")
32+
os.Exit(1)
33+
}
34+
35+
helmOptions := helmclient.Options{
36+
Namespace: namespace,
37+
RepositoryCache: "/tmp/.helmcache",
38+
RepositoryConfig: "/tmp/.helmrepo",
39+
Debug: false,
40+
Linting: false, // Change this to false if you don't want linting.
41+
}
42+
43+
//Helm client init logic
44+
opt := &helmclient.KubeConfClientOptions{
45+
Options: &helmOptions,
46+
KubeContext: "",
47+
KubeConfig: kubeConfig,
48+
}
49+
50+
helmClient, err := helmclient.NewClientFromKubeConf(opt)
51+
if err != nil {
52+
fmt.Println("Cannot create client from kubeConfig")
53+
os.Exit(1)
54+
}
55+
56+
// List Helm releases
57+
releases, err := helmClient.ListReleasesByStateMask(action.ListAll)
58+
if err != nil {
59+
fmt.Printf("Cannot list releases: %s\n", err)
60+
os.Exit(1)
61+
}
62+
63+
writer := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight)
64+
fmt.Fprintln(writer, "NAME\tNAMESPACE\tREVISION\tUPDATED\tSTATUS\tCHART\tAPP VERSION")
65+
66+
for _, release := range releases {
67+
fmt.Fprintf(writer, "%s\t%s\t%d\t%s\t%s\t%s\t%s\n", release.Name, release.Namespace, release.Version, release.Info.LastDeployed.String(), release.Info.Status.String(), release.Chart.Name(), release.Chart.Metadata.Version)
68+
}
69+
70+
writer.Flush()
71+
72+
},
73+
}
74+
75+
func init() {
76+
ciReleaseCmd.AddCommand(ciReleaseListCmd)
77+
78+
ciReleaseListCmd.Flags().StringP("namespace", "n", "", "Project name (namespace, i.e. \"drupal-project\")")
79+
}

cmd/root.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"log"
77
"os"
88
"os/exec"
9+
"strings"
910

1011
"github.com/spf13/cobra"
1112
"github.com/wunderio/silta-cli/internal/common"
@@ -36,6 +37,19 @@ func init() {
3637
rootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "Print variables, do not execute external commands, rather print them")
3738
rootCmd.PersistentFlags().BoolVar(&useEnv, "use-env", true, "Use environment variables for value assignment")
3839

40+
// Rewrite per-cluster environment variables
41+
cluster_id := os.Getenv("SILTA_CLUSTER_ID")
42+
if len(cluster_id) > 0 {
43+
// iterate all environment variables, search for keys with "<${SILTA_CLUSTER_ID}>_" prefix
44+
// and rewrite them to the corresponding keys without the prefix
45+
for _, e := range os.Environ() {
46+
pair := strings.SplitN(e, "=", 2)
47+
if strings.HasPrefix(pair[0], cluster_id+"_") {
48+
os.Setenv(strings.TrimPrefix(pair[0], cluster_id+"_"), pair[1])
49+
}
50+
}
51+
}
52+
3953
// Load configuration
4054
configStore := common.ConfigStore()
4155

docs/silta.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ Silta CLI
1616
* [silta ci](silta_ci.md) - Silta CI Commands
1717
* [silta cloud](silta_cloud.md) - Kubernetes cloud related commands
1818
* [silta completion](silta_completion.md) - Generate the autocompletion script for the specified shell
19+
* [silta config](silta_config.md) - Silta configuration commands
1920
* [silta doc](silta_doc.md) - Generate menu documentation markdown
21+
* [silta scripts](silta_scripts.md) - Convenience scripts for silta
2022
* [silta secrets](silta_secrets.md) - Manage encrypted secret files
2123
* [silta tools](silta_tools.md) - CI tooling
2224
* [silta version](silta_version.md) - Silta CLI version

docs/silta_ci_release.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ silta ci release [flags]
2525
* [silta ci release clean-failed](silta_ci_release_clean-failed.md) - Clean failed releases
2626
* [silta ci release delete](silta_ci_release_delete.md) - Delete a release
2727
* [silta ci release deploy](silta_ci_release_deploy.md) - Deploy release
28+
* [silta ci release diff](silta_ci_release_diff.md) - Diff release resources
2829
* [silta ci release environmentname](silta_ci_release_environmentname.md) - Return environment name
2930
* [silta ci release info](silta_ci_release_info.md) - Print release information
31+
* [silta ci release list](silta_ci_release_list.md) - List releases
3032
* [silta ci release name](silta_ci_release_name.md) - Return release name
3133
* [silta ci release validate](silta_ci_release_validate.md) - Validate release
3234
* [silta ci release wakeup](silta_ci_release_wakeup.md) - Wake up a downscaled release

docs/silta_ci_release_delete.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ silta ci release delete [flags]
99
### Options
1010

1111
```
12-
--delete-pvcs Delete PVCs (default: false)
12+
--delete-pvcs Delete PVCs (default: true) (default true)
1313
-h, --help help for delete
1414
--namespace string Project name (namespace, i.e. "drupal-project")
1515
--release-name string Release name

docs/silta_ci_release_deploy.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Release deployment
99
* Chart allows prepending extra configuration (to helm --values line) via
1010
"SILTA_<chart_name>_CONFIG_VALUES" environment variable. It has to be a
1111
base64 encoded string of a silta configuration yaml file.
12+
13+
* If IMAGE_PULL_SECRET is set (base64 encoded), it will be added to the
14+
release values as imagePullSecret.
1215

1316

1417
```
@@ -20,7 +23,7 @@ silta ci release deploy [flags]
2023
```
2124
--branchname string Repository branchname that will be used for release name and environment name creation
2225
--chart-name string Chart name
23-
--chart-repository string Chart repository
26+
--chart-repository string Chart repository (default "https://storage.googleapis.com/charts.wdr.io")
2427
--chart-version string Deploy a specific chart version
2528
--cluster-domain string Base domain for cluster urls (i.e. dev.example.com)
2629
--cluster-type string Cluster type (i.e. gke, aws, aks, other)

docs/silta_ci_release_diff.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
## silta ci release diff
2+
3+
Diff release resources
4+
5+
### Synopsis
6+
7+
Release diff command is used to compare the resources of a release with the current state of the cluster.
8+
9+
* Chart allows prepending extra configuration (to helm --values line) via
10+
"SILTA_<chart_name>_CONFIG_VALUES" environment variable. It has to be a
11+
base64 encoded string of a silta configuration yaml file.
12+
13+
* If IMAGE_PULL_SECRET is set (base64 encoded), it will be added to the
14+
release values as imagePullSecret.
15+
16+
17+
```
18+
silta ci release diff [flags]
19+
```
20+
21+
### Options
22+
23+
```
24+
--branchname string Repository branchname that will be used for release name and environment name creation
25+
--chart-name string Chart name
26+
--chart-repository string Chart repository (default "https://storage.googleapis.com/charts.wdr.io")
27+
--chart-version string Diff a specific chart version
28+
--cluster-domain string Base domain for cluster urls (i.e. dev.example.com)
29+
--cluster-type string Cluster type (i.e. gke, aws, aks, other)
30+
--db-root-pass string Database password for root account
31+
--db-user-pass string Database password for user account
32+
--gitauth-password string Gitauth server password
33+
--gitauth-username string Gitauth server username
34+
--helm-flags string Extra flags for helm release
35+
-h, --help help for diff
36+
--namespace string Project name (namespace, i.e. "drupal-project")
37+
--nginx-image-url string PHP image url
38+
--php-image-url string PHP image url
39+
--release-name string Release name
40+
--release-suffix string Release name suffix for environment name creation
41+
--repository-url string Repository url (i.e. [email protected]:wunderio/silta.git)
42+
--shell-image-url string PHP image url
43+
--silta-config string Silta release helm chart values
44+
--silta-environment-name string Environment name override based on branchname and release-suffix. Used in some helm charts.
45+
--vpc-native string VPC-native cluster (GKE specific)
46+
--vpn-ip string VPN IP for basic auth allow list
47+
```
48+
49+
### Options inherited from parent commands
50+
51+
```
52+
--debug Print variables, do not execute external commands, rather print them
53+
--use-env Use environment variables for value assignment (default true)
54+
```
55+
56+
### SEE ALSO
57+
58+
* [silta ci release](silta_ci_release.md) - CI release related commands
59+

docs/silta_ci_release_list.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## silta ci release list
2+
3+
List releases
4+
5+
```
6+
silta ci release list [flags]
7+
```
8+
9+
### Options
10+
11+
```
12+
-h, --help help for list
13+
-n, --namespace string Project name (namespace, i.e. "drupal-project")
14+
```
15+
16+
### Options inherited from parent commands
17+
18+
```
19+
--debug Print variables, do not execute external commands, rather print them
20+
--use-env Use environment variables for value assignment (default true)
21+
```
22+
23+
### SEE ALSO
24+
25+
* [silta ci release](silta_ci_release.md) - CI release related commands
26+

0 commit comments

Comments
 (0)