Compare commits
2 Commits
v0.9.0
...
eks-suppor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c1ed849ab | ||
|
|
d8d2e33b20 |
@@ -30,7 +30,9 @@ Installations are triggered when the `helm_command` setting is "upgrade." They c
|
|||||||
| chart | string | yes | The chart to use for this installation. |
|
| chart | string | yes | The chart to use for this installation. |
|
||||||
| release | string | yes | The release name for helm to use. |
|
| release | string | yes | The release name for helm to use. |
|
||||||
| api_server | string | yes | API endpoint for the Kubernetes cluster. |
|
| api_server | string | yes | API endpoint for the Kubernetes cluster. |
|
||||||
| kubernetes_token | string | yes | Token for authenticating to Kubernetes. |
|
| kubernetes_token | string | yes, unless using EKS | Token for authenticating to Kubernetes. |
|
||||||
|
| eks_cluster | string | | AWS EKS cluster ID. |
|
||||||
|
| eks_role_arn | string | | AWS IAM role ARN for EKS authentication. |
|
||||||
| service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. |
|
| service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. |
|
||||||
| kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. |
|
| kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. |
|
||||||
| chart_version | string | | Specific chart version to install. |
|
| chart_version | string | | Specific chart version to install. |
|
||||||
@@ -52,7 +54,9 @@ Uninstallations are triggered when the `helm_command` setting is "uninstall" or
|
|||||||
|------------------------|----------|----------|---------|
|
|------------------------|----------|----------|---------|
|
||||||
| release | string | yes | The release name for helm to use. |
|
| release | string | yes | The release name for helm to use. |
|
||||||
| api_server | string | yes | API endpoint for the Kubernetes cluster. |
|
| api_server | string | yes | API endpoint for the Kubernetes cluster. |
|
||||||
| kubernetes_token | string | yes | Token for authenticating to Kubernetes. |
|
| kubernetes_token | string | yes, unless using EKS | Token for authenticating to Kubernetes. |
|
||||||
|
| eks_cluster | string | | AWS EKS cluster ID. |
|
||||||
|
| eks_role_arn | string | | AWS IAM role ARN for EKS authentication. |
|
||||||
| service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. |
|
| service_account | string | | Service account for authenticating to Kubernetes. Default is `helm`. |
|
||||||
| kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. |
|
| kubernetes_certificate | string | | Base64 encoded TLS certificate used by the Kubernetes cluster's certificate authority. |
|
||||||
| dry_run | boolean | | Pass `--dry-run` to `helm uninstall`. |
|
| dry_run | boolean | | Pass `--dry-run` to `helm uninstall`. |
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ type Config struct {
|
|||||||
ValuesFiles []string `split_words:"true"` // Arguments to pass to --values in applicable helm commands
|
ValuesFiles []string `split_words:"true"` // Arguments to pass to --values in applicable helm commands
|
||||||
Namespace string `` // Kubernetes namespace for all helm commands
|
Namespace string `` // Kubernetes namespace for all helm commands
|
||||||
KubeToken string `envconfig:"KUBERNETES_TOKEN"` // Kubernetes authentication token to put in .kube/config
|
KubeToken string `envconfig:"KUBERNETES_TOKEN"` // Kubernetes authentication token to put in .kube/config
|
||||||
|
EKSCluster string `envconfig:"EKS_CLUSTER"` // AWS EKS Cluster ID to put in .kube/config
|
||||||
|
EKSRoleARN string `envconfig:"EKS_ROLE_ARN"` // AWS IAM role resource name to put in .kube/config
|
||||||
SkipTLSVerify bool `envconfig:"SKIP_TLS_VERIFY"` // Put insecure-skip-tls-verify in .kube/config
|
SkipTLSVerify bool `envconfig:"SKIP_TLS_VERIFY"` // Put insecure-skip-tls-verify in .kube/config
|
||||||
Certificate string `envconfig:"KUBERNETES_CERTIFICATE"` // The Kubernetes cluster CA's self-signed certificate (must be base64-encoded)
|
Certificate string `envconfig:"KUBERNETES_CERTIFICATE"` // The Kubernetes cluster CA's self-signed certificate (must be base64-encoded)
|
||||||
APIServer string `envconfig:"API_SERVER"` // The Kubernetes cluster's API endpoint
|
APIServer string `envconfig:"API_SERVER"` // The Kubernetes cluster's API endpoint
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ func initKube(cfg Config) []Step {
|
|||||||
APIServer: cfg.APIServer,
|
APIServer: cfg.APIServer,
|
||||||
ServiceAccount: cfg.ServiceAccount,
|
ServiceAccount: cfg.ServiceAccount,
|
||||||
Token: cfg.KubeToken,
|
Token: cfg.KubeToken,
|
||||||
|
EKSCluster: cfg.EKSCluster,
|
||||||
|
EKSRoleARN: cfg.EKSRoleARN,
|
||||||
TemplateFile: kubeConfigTemplate,
|
TemplateFile: kubeConfigTemplate,
|
||||||
ConfigFile: kubeConfigFile,
|
ConfigFile: kubeConfigFile,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -212,6 +212,8 @@ func (suite *PlanTestSuite) TestInitKube() {
|
|||||||
Certificate: "b2Ygd29rZW5lc3MK",
|
Certificate: "b2Ygd29rZW5lc3MK",
|
||||||
APIServer: "123.456.78.9",
|
APIServer: "123.456.78.9",
|
||||||
ServiceAccount: "helmet",
|
ServiceAccount: "helmet",
|
||||||
|
EKSCluster: "eks_reader",
|
||||||
|
EKSRoleARN: "arn:aws:iam::9631085:role/eksSpangleRole",
|
||||||
}
|
}
|
||||||
|
|
||||||
steps := initKube(cfg)
|
steps := initKube(cfg)
|
||||||
@@ -225,6 +227,8 @@ func (suite *PlanTestSuite) TestInitKube() {
|
|||||||
APIServer: "123.456.78.9",
|
APIServer: "123.456.78.9",
|
||||||
ServiceAccount: "helmet",
|
ServiceAccount: "helmet",
|
||||||
Token: "cXVlZXIgY2hhcmFjdGVyCg==",
|
Token: "cXVlZXIgY2hhcmFjdGVyCg==",
|
||||||
|
EKSCluster: "eks_reader",
|
||||||
|
EKSRoleARN: "arn:aws:iam::9631085:role/eksSpangleRole",
|
||||||
TemplateFile: kubeConfigTemplate,
|
TemplateFile: kubeConfigTemplate,
|
||||||
ConfigFile: kubeConfigFile,
|
ConfigFile: kubeConfigFile,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ type InitKube struct {
|
|||||||
APIServer string
|
APIServer string
|
||||||
ServiceAccount string
|
ServiceAccount string
|
||||||
Token string
|
Token string
|
||||||
|
EKSCluster string
|
||||||
|
EKSRoleARN string
|
||||||
TemplateFile string
|
TemplateFile string
|
||||||
ConfigFile string
|
ConfigFile string
|
||||||
|
|
||||||
@@ -30,6 +32,8 @@ type kubeValues struct {
|
|||||||
Namespace string
|
Namespace string
|
||||||
ServiceAccount string
|
ServiceAccount string
|
||||||
Token string
|
Token string
|
||||||
|
EKSCluster string
|
||||||
|
EKSRoleARN string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute generates a kubernetes config file from drone-helm3's template.
|
// Execute generates a kubernetes config file from drone-helm3's template.
|
||||||
@@ -48,9 +52,12 @@ func (i *InitKube) Prepare(cfg Config) error {
|
|||||||
if i.APIServer == "" {
|
if i.APIServer == "" {
|
||||||
return errors.New("an API Server is needed to deploy")
|
return errors.New("an API Server is needed to deploy")
|
||||||
}
|
}
|
||||||
if i.Token == "" {
|
if i.Token == "" && i.EKSCluster == "" {
|
||||||
return errors.New("token is needed to deploy")
|
return errors.New("token is needed to deploy")
|
||||||
}
|
}
|
||||||
|
if i.Token != "" && i.EKSCluster != "" {
|
||||||
|
return errors.New("token cannot be used simultaneously with eksCluster")
|
||||||
|
}
|
||||||
|
|
||||||
if i.ServiceAccount == "" {
|
if i.ServiceAccount == "" {
|
||||||
i.ServiceAccount = "helm"
|
i.ServiceAccount = "helm"
|
||||||
@@ -70,6 +77,8 @@ func (i *InitKube) Prepare(cfg Config) error {
|
|||||||
APIServer: i.APIServer,
|
APIServer: i.APIServer,
|
||||||
ServiceAccount: i.ServiceAccount,
|
ServiceAccount: i.ServiceAccount,
|
||||||
Token: i.Token,
|
Token: i.Token,
|
||||||
|
EKSCluster: i.EKSCluster,
|
||||||
|
EKSRoleARN: i.EKSRoleARN,
|
||||||
Namespace: cfg.Namespace,
|
Namespace: cfg.Namespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package run
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
yaml "gopkg.in/yaml.v2"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -58,59 +57,6 @@ namespace: Cisco
|
|||||||
suite.Equal(want, string(conf))
|
suite.Equal(want, string(conf))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() {
|
|
||||||
configFile, err := tempfile("kubeconfig********.yml", "")
|
|
||||||
defer os.Remove(configFile.Name())
|
|
||||||
suite.Require().NoError(err)
|
|
||||||
|
|
||||||
cfg := Config{
|
|
||||||
Namespace: "marshmallow",
|
|
||||||
}
|
|
||||||
init := InitKube{
|
|
||||||
ConfigFile: configFile.Name(),
|
|
||||||
TemplateFile: "../../assets/kubeconfig.tpl", // the actual kubeconfig template
|
|
||||||
APIServer: "https://kube.cluster/peanut",
|
|
||||||
ServiceAccount: "chef",
|
|
||||||
Token: "eWVhaCB3ZSB0b2tpbic=",
|
|
||||||
Certificate: "d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE",
|
|
||||||
}
|
|
||||||
suite.Require().NoError(init.Prepare(cfg))
|
|
||||||
suite.Require().NoError(init.Execute(cfg))
|
|
||||||
|
|
||||||
contents, err := ioutil.ReadFile(configFile.Name())
|
|
||||||
suite.Require().NoError(err)
|
|
||||||
|
|
||||||
// each setting should be reflected in the generated file
|
|
||||||
expectations := []string{
|
|
||||||
"namespace: marshmallow",
|
|
||||||
"server: https://kube.cluster/peanut",
|
|
||||||
"user: chef",
|
|
||||||
"name: chef",
|
|
||||||
"token: eWVhaCB3ZSB0b2tpbic",
|
|
||||||
"certificate-authority-data: d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE",
|
|
||||||
}
|
|
||||||
for _, expected := range expectations {
|
|
||||||
suite.Contains(string(contents), expected)
|
|
||||||
}
|
|
||||||
|
|
||||||
// the generated config should be valid yaml, with no repeated keys
|
|
||||||
conf := map[string]interface{}{}
|
|
||||||
suite.NoError(yaml.UnmarshalStrict(contents, &conf))
|
|
||||||
|
|
||||||
// test the other branch of the certificate/SkipTLSVerify conditional
|
|
||||||
init.SkipTLSVerify = true
|
|
||||||
init.Certificate = ""
|
|
||||||
|
|
||||||
suite.Require().NoError(init.Prepare(cfg))
|
|
||||||
suite.Require().NoError(init.Execute(cfg))
|
|
||||||
contents, err = ioutil.ReadFile(configFile.Name())
|
|
||||||
suite.Require().NoError(err)
|
|
||||||
suite.Contains(string(contents), "insecure-skip-tls-verify: true")
|
|
||||||
|
|
||||||
conf = map[string]interface{}{}
|
|
||||||
suite.NoError(yaml.UnmarshalStrict(contents, &conf))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (suite *InitKubeTestSuite) TestPrepareParseError() {
|
func (suite *InitKubeTestSuite) TestPrepareParseError() {
|
||||||
templateFile, err := tempfile("kubeconfig********.yml.tpl", `{{ NonexistentFunction }}`)
|
templateFile, err := tempfile("kubeconfig********.yml.tpl", `{{ NonexistentFunction }}`)
|
||||||
defer os.Remove(templateFile.Name())
|
defer os.Remove(templateFile.Name())
|
||||||
@@ -187,6 +133,33 @@ func (suite *InitKubeTestSuite) TestPrepareRequiredConfig() {
|
|||||||
suite.Error(init.Prepare(cfg), "Token should be required.")
|
suite.Error(init.Prepare(cfg), "Token should be required.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *InitKubeTestSuite) TestPrepareEKSConfig() {
|
||||||
|
templateFile, err := tempfile("kubeconfig********.yml.tpl", "hurgity burgity")
|
||||||
|
defer os.Remove(templateFile.Name())
|
||||||
|
suite.Require().Nil(err)
|
||||||
|
|
||||||
|
configFile, err := tempfile("kubeconfig********.yml", "")
|
||||||
|
defer os.Remove(configFile.Name())
|
||||||
|
suite.Require().Nil(err)
|
||||||
|
|
||||||
|
init := InitKube{
|
||||||
|
TemplateFile: templateFile.Name(),
|
||||||
|
ConfigFile: configFile.Name(),
|
||||||
|
APIServer: "eks.aws.amazonaws.com",
|
||||||
|
EKSCluster: "it-is-an-eks-parrot",
|
||||||
|
EKSRoleARN: "arn:aws:iam::19691207:role/mrPraline",
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := Config{}
|
||||||
|
|
||||||
|
suite.NoError(init.Prepare(cfg))
|
||||||
|
suite.Equal(init.values.EKSCluster, "it-is-an-eks-parrot")
|
||||||
|
suite.Equal(init.values.EKSRoleARN, "arn:aws:iam::19691207:role/mrPraline")
|
||||||
|
|
||||||
|
init.Token = "cGluaW5nIGZvciB0aGUgZmrDtnJkcw=="
|
||||||
|
suite.EqualError(init.Prepare(cfg), "token cannot be used simultaneously with eksCluster")
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *InitKubeTestSuite) TestPrepareDefaultsServiceAccount() {
|
func (suite *InitKubeTestSuite) TestPrepareDefaultsServiceAccount() {
|
||||||
templateFile, err := tempfile("kubeconfig********.yml.tpl", "hurgity burgity")
|
templateFile, err := tempfile("kubeconfig********.yml.tpl", "hurgity burgity")
|
||||||
defer os.Remove(templateFile.Name())
|
defer os.Remove(templateFile.Name())
|
||||||
|
|||||||
109
internal/run/kubeconfig_test.go
Normal file
109
internal/run/kubeconfig_test.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package run
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KubeconfigTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
configFile *os.File
|
||||||
|
initKube InitKube
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) BeforeTest(_, _ string) {
|
||||||
|
file, err := ioutil.TempFile("", "kubeconfig********.yml")
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
file.Close()
|
||||||
|
suite.configFile = file
|
||||||
|
|
||||||
|
// set up an InitKube with the bare minimum configuration
|
||||||
|
suite.initKube = InitKube{
|
||||||
|
ConfigFile: file.Name(),
|
||||||
|
TemplateFile: "../../assets/kubeconfig.tpl", // the actual kubeconfig template
|
||||||
|
APIServer: "a",
|
||||||
|
Token: "b",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) AfterTest(_, _ string) {
|
||||||
|
if suite.configFile != nil {
|
||||||
|
os.Remove(suite.configFile.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKubeconfigTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(KubeconfigTestSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsNamespace() {
|
||||||
|
cfg := Config{
|
||||||
|
Namespace: "marshmallow",
|
||||||
|
}
|
||||||
|
contents := suite.generateKubeconfig(cfg)
|
||||||
|
suite.Contains(contents, "namespace: marshmallow")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsAPIServer() {
|
||||||
|
suite.initKube.APIServer = "https://kube.cluster/peanut"
|
||||||
|
contents := suite.generateKubeconfig(Config{})
|
||||||
|
suite.Contains(contents, "server: https://kube.cluster/peanut")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsServiceAccount() {
|
||||||
|
suite.initKube.ServiceAccount = "chef"
|
||||||
|
contents := suite.generateKubeconfig(Config{})
|
||||||
|
suite.Contains(contents, "user: chef")
|
||||||
|
suite.Contains(contents, "name: chef")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsToken() {
|
||||||
|
suite.initKube.Token = "eWVhaCB3ZSB0b2tpbic"
|
||||||
|
contents := suite.generateKubeconfig(Config{})
|
||||||
|
suite.Contains(contents, "token: eWVhaCB3ZSB0b2tpbic")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsCertificate() {
|
||||||
|
suite.initKube.Certificate = "d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE"
|
||||||
|
contents := suite.generateKubeconfig(Config{})
|
||||||
|
suite.Contains(contents, "certificate-authority-data: d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsSkipTLSVerify() {
|
||||||
|
suite.initKube.SkipTLSVerify = true
|
||||||
|
contents := suite.generateKubeconfig(Config{})
|
||||||
|
suite.Contains(contents, "insecure-skip-tls-verify: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsEKSCluster() {
|
||||||
|
suite.initKube.Token = ""
|
||||||
|
suite.initKube.EKSCluster = "it-is-an-eks-parrot"
|
||||||
|
contents := suite.generateKubeconfig(Config{})
|
||||||
|
suite.Contains(contents, "command: aws-iam-authenticator")
|
||||||
|
suite.Contains(contents, `- "it-is-an-eks-parrot"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) TestSetsEKSRoleARN() {
|
||||||
|
suite.initKube.Token = ""
|
||||||
|
suite.initKube.EKSCluster = "it-is-an-eks-parrot"
|
||||||
|
suite.initKube.EKSRoleARN = "arn:aws:iam::19691207:role/mrPraline"
|
||||||
|
contents := suite.generateKubeconfig(Config{})
|
||||||
|
suite.Contains(contents, `- "-r"`)
|
||||||
|
suite.Contains(contents, `- "arn:aws:iam::19691207:role/mrPraline"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *KubeconfigTestSuite) generateKubeconfig(cfg Config) string {
|
||||||
|
suite.Require().NoError(suite.initKube.Prepare(cfg))
|
||||||
|
suite.Require().NoError(suite.initKube.Execute(cfg))
|
||||||
|
|
||||||
|
contents, err := ioutil.ReadFile(suite.configFile.Name())
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
conf := map[string]interface{}{}
|
||||||
|
suite.NoError(yaml.UnmarshalStrict(contents, &conf))
|
||||||
|
|
||||||
|
return string(contents)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user