Skip to content

Commit

Permalink
Add Consul Service Mesh as an installable app
Browse files Browse the repository at this point in the history
Signed-off-by: Johan Siebens <[email protected]>
  • Loading branch information
jsiebens authored and alexellis committed Oct 30, 2020
1 parent ff1487a commit 55dfac7
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ Available Commands:
argocd Install argocd
cert-manager Install cert-manager
chart Install the specified helm chart
consul-connect Install Consul Service Mesh
cron-connector Install cron-connector for OpenFaaS
crossplane Install Crossplane
docker-registry Install a Docker registry
Expand Down
172 changes: 172 additions & 0 deletions cmd/apps/consul_app.go
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
4 changes: 4 additions & 0 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ func GetApps() map[string]ArkadeApp {
arkadeApps["registry-creds"] = NewArkadeApp(apps.MakeInstallRegistryCredsOperator, apps.RegistryCredsOperatorInfoMsg)
arkadeApps["gitea"] = NewArkadeApp(apps.MakeInstallGitea, apps.GiteaInfoMsg)
arkadeApps["kong-ingress"] = NewArkadeApp(apps.MakeInstallKongIngress, apps.KongIngressInfoMsg)
<<<<<<< HEAD
arkadeApps["sealed-secret"] = NewArkadeApp(apps.MakeInstallSealedSecrets, apps.SealedSecretsInfoMsg)
=======
arkadeApps["consul-connect"] = NewArkadeApp(apps.MakeInstallConsul, apps.ConsulInfoMsg)
>>>>>>> Add Consul Service Mesh as an installable app
// Special "chart" app - let a user deploy any helm chart
arkadeApps["chart"] = NewArkadeApp(apps.MakeInstallChart, "")
return arkadeApps
Expand Down

0 comments on commit 55dfac7

Please sign in to comment.