forked from alexellis/arkade
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Consul Service Mesh as an installable app
Signed-off-by: Johan Siebens <[email protected]>
- Loading branch information
Showing
3 changed files
with
177 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
// Copyright (c) arkade author(s) 2020. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
package apps | ||
|
||
import ( | ||
"crypto/rand" | ||
"encoding/base64" | ||
"fmt" | ||
"github.com/alexellis/arkade/pkg/apps" | ||
"github.com/alexellis/arkade/pkg/types" | ||
"log" | ||
"os" | ||
"path" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/alexellis/arkade/pkg/k8s" | ||
|
||
"github.com/alexellis/arkade/pkg" | ||
"github.com/alexellis/arkade/pkg/config" | ||
"github.com/alexellis/arkade/pkg/env" | ||
"github.com/alexellis/arkade/pkg/helm" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func MakeInstallConsul() *cobra.Command { | ||
var consul = &cobra.Command{ | ||
Use: "consul-connect", | ||
Short: "Install Consul Service Mesh", | ||
Long: `Install Consul Service Mesh to any Kubernetes cluster`, | ||
Example: ` arkade install consul-connect`, | ||
SilenceUsage: true, | ||
} | ||
|
||
consul.Flags().StringP("namespace", "n", "consul-system", "The namespace used for installation") | ||
consul.Flags().Bool("update-repo", true, "Update the helm repo") | ||
consul.Flags().StringP("datacenter", "d", "dc1", "The name of the datacenter that the agents should register as") | ||
consul.Flags().Bool("enable-connect-injector", true, "If true, all the resources necessary for the Connect injector process to run will be installed") | ||
consul.Flags().Bool("enable-tls-encryption", true, "If true, TLS encryption across the cluster to verify authenticity of the Consul servers and clients is enabled") | ||
consul.Flags().Bool("enable-gossip-encryption", true, "If true, Consul's gossip encryption is enabled") | ||
consul.Flags().String("gossip-encryption-key", "", "The gossip encryption key; when empty, a new, random key is generated") | ||
consul.Flags().Bool("manage-system-acls", true, "If true, the ACL tokens and policies for all Consul and consul-k8s components will automatically be managed") | ||
consul.Flags().StringArray("set", []string{}, "Use custom flags or override existing flags \n(example --set=image=org/repo:tag)") | ||
|
||
consul.RunE = func(command *cobra.Command, args []string) error { | ||
updateRepo, _ := consul.Flags().GetBool("update-repo") | ||
|
||
arch := k8s.GetNodeArchitecture() | ||
fmt.Printf("Node architecture: %q\n", arch) | ||
|
||
if arch != IntelArch { | ||
return fmt.Errorf(OnlyIntelArch) | ||
} | ||
|
||
userPath, err := config.InitUserDir() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
clientArch, clientOS := env.GetClientArch() | ||
|
||
fmt.Printf("Client: %s, %s\n", clientArch, clientOS) | ||
log.Printf("User dir established as: %s\n", userPath) | ||
|
||
namespace, _ := consul.Flags().GetString("namespace") | ||
|
||
overrides := map[string]string{} | ||
overrides["global.name"] = "consul" | ||
|
||
datacenter, _ := command.Flags().GetString("datacenter") | ||
overrides["global.datacenter"] = datacenter | ||
|
||
connectInjectorEnabled, _ := command.Flags().GetBool("enable-connect-injector") | ||
overrides["connectInject.enabled"] = strings.ToLower(strconv.FormatBool(connectInjectorEnabled)) | ||
|
||
tlsEnabled, _ := command.Flags().GetBool("enable-tls-encryption") | ||
overrides["global.tls.enabled"] = strings.ToLower(strconv.FormatBool(tlsEnabled)) | ||
|
||
manageSystemACLs, _ := command.Flags().GetBool("manage-system-acls") | ||
overrides["global.acls.manageSystemACLs"] = strings.ToLower(strconv.FormatBool(manageSystemACLs)) | ||
|
||
gossipEncryptionEnabled, _ := command.Flags().GetBool("enable-gossip-encryption") | ||
gossipEncryptionKey, _ := command.Flags().GetString("gossip-encryption-key") | ||
|
||
if gossipEncryptionEnabled && gossipEncryptionKey == "" { | ||
gossipEncryptionKey, err = generateGossipEncryptionKey() | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
_, nsErr := k8s.KubectlTask("create", "namespace", namespace) | ||
if nsErr != nil && !strings.Contains(nsErr.Error(), "AlreadyExists") { | ||
return nsErr | ||
} | ||
|
||
if gossipEncryptionEnabled { | ||
res, err := k8s.KubectlTask("create", "secret", "generic", | ||
"consul-gossip-encryption-key", | ||
"--namespace="+namespace, | ||
"--from-literal", "key="+gossipEncryptionKey) | ||
if err != nil { | ||
return err | ||
} else if len(res.Stderr) > 0 && strings.Contains(res.Stderr, "AlreadyExists") { | ||
fmt.Println("[Warning] secret consul-gossip-encryption-key already exists and will be used.") | ||
} else if len(res.Stderr) > 0 { | ||
return fmt.Errorf("error from kubectl\n%q", res.Stderr) | ||
} | ||
|
||
overrides["global.gossipEncryption.secretName"] = "consul-gossip-encryption-key" | ||
overrides["global.gossipEncryption.secretKey"] = "key" | ||
} | ||
|
||
customFlags, _ := command.Flags().GetStringArray("set") | ||
|
||
if err := mergeFlags(overrides, customFlags); err != nil { | ||
return err | ||
} | ||
|
||
consulOptions := types.DefaultInstallOptions(). | ||
WithNamespace(namespace). | ||
WithHelmPath(path.Join(userPath, ".helm")). | ||
WithHelmRepo("hashicorp/consul"). | ||
WithHelmURL("https://helm.releases.hashicorp.com"). | ||
WithOverrides(overrides). | ||
WithHelmUpdateRepo(updateRepo) | ||
|
||
if command.Flags().Changed("kubeconfig") { | ||
kubeconfigPath, _ := command.Flags().GetString("kubeconfig") | ||
consulOptions.WithKubeconfigPath(kubeconfigPath) | ||
} | ||
|
||
os.Setenv("HELM_HOME", path.Join(userPath, ".helm")) | ||
|
||
_, err = helm.TryDownloadHelm(userPath, clientArch, clientOS) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = apps.MakeInstallChart(consulOptions) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Println(consulInstallMsg) | ||
return nil | ||
} | ||
|
||
return consul | ||
} | ||
|
||
func generateGossipEncryptionKey() (string, error) { | ||
key := make([]byte, 32) | ||
n, err := rand.Reader.Read(key) | ||
if err != nil { | ||
return "", err | ||
} | ||
if n != 32 { | ||
return "", fmt.Errorf("couldn't read enough entropy, generate more entropy") | ||
} | ||
|
||
return base64.StdEncoding.EncodeToString(key), nil | ||
} | ||
|
||
const ConsulInfoMsg = `# Find out more at: | ||
# https://www.consul.io/docs/k8s` | ||
|
||
const consulInstallMsg = `======================================================================= | ||
= Consul has been installed. = | ||
=======================================================================` + | ||
"\n\n" + ConsulInfoMsg + "\n\n" + pkg.ThanksForUsing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters