You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by zh...@apache.org on 2021/11/22 02:18:33 UTC
[apisix-ingress-controller] branch master updated: feat: support environment variable in config file (#745)
This is an automated email from the ASF dual-hosted git repository.
zhangjintao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git
The following commit(s) were added to refs/heads/master by this push:
new 9f2cd7f feat: support environment variable in config file (#745)
9f2cd7f is described below
commit 9f2cd7f856f1879ae2586f2a84f4f39d2654996d
Author: Nic <qi...@api7.ai>
AuthorDate: Mon Nov 22 10:18:27 2021 +0800
feat: support environment variable in config file (#745)
---
pkg/config/config.go | 24 ++++++-
pkg/config/config_test.go | 107 +++++++++++++++++++++++++++++++
test/e2e/config/config.go | 84 ++++++++++++++++++++++++
test/e2e/{e2e.go => config/manifests.go} | 32 ++++++---
test/e2e/e2e.go | 1 +
test/e2e/go.mod | 1 +
test/e2e/scaffold/ingress.go | 2 +-
test/e2e/scaffold/k8s.go | 8 +++
test/e2e/scaffold/scaffold.go | 2 +-
9 files changed, 248 insertions(+), 13 deletions(-)
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 9cd19c1..1f8a3dd 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -15,11 +15,14 @@
package config
import (
+ "bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
+ "os"
"strings"
+ "text/template"
"time"
"gopkg.in/yaml.v2"
@@ -140,10 +143,27 @@ func NewConfigFromFile(filename string) (*Config, error) {
return nil, err
}
+ envVarMap := map[string]string{}
+ for _, e := range os.Environ() {
+ pair := strings.SplitN(e, "=", 2)
+ envVarMap[pair[0]] = pair[1]
+ }
+
+ tpl := template.New("text").Option("missingkey=error")
+ tpl, err = tpl.Parse(string(data))
+ if err != nil {
+ return nil, fmt.Errorf("error parsing configuration template %v", err)
+ }
+ buf := bytes.NewBufferString("")
+ err = tpl.Execute(buf, envVarMap)
+ if err != nil {
+ return nil, fmt.Errorf("error execute configuration template %v", err)
+ }
+
if strings.HasSuffix(filename, ".yaml") || strings.HasSuffix(filename, ".yml") {
- err = yaml.Unmarshal(data, cfg)
+ err = yaml.Unmarshal(buf.Bytes(), cfg)
} else {
- err = json.Unmarshal(data, cfg)
+ err = json.Unmarshal(buf.Bytes(), cfg)
}
if err != nil {
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index df07821..8877c7a 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -103,6 +103,113 @@ apisix:
assert.Equal(t, cfg, newCfg, "bad configuration")
}
+func TestConfigWithEnvVar(t *testing.T) {
+ cfg := &Config{
+ LogLevel: "warn",
+ LogOutput: "stdout",
+ HTTPListen: ":9090",
+ HTTPSListen: ":9443",
+ CertFilePath: "/etc/webhook/certs/cert.pem",
+ KeyFilePath: "/etc/webhook/certs/key.pem",
+ EnableProfiling: true,
+ Kubernetes: KubernetesConfig{
+ ResyncInterval: types.TimeDuration{Duration: time.Hour},
+ Kubeconfig: "",
+ AppNamespaces: []string{""},
+ ElectionID: "my-election-id",
+ IngressClass: IngressClass,
+ IngressVersion: IngressNetworkingV1,
+ ApisixRouteVersion: ApisixRouteV2alpha1,
+ },
+ APISIX: APISIXConfig{
+ DefaultClusterName: "default",
+ DefaultClusterBaseURL: "http://127.0.0.1:8080/apisix",
+ DefaultClusterAdminKey: "123456",
+ },
+ }
+
+ defaultClusterBaseURLEnvName := "DEFAULT_CLUSTER_BASE_URL"
+ defaultClusterAdminKeyEnvName := "DEFAULT_CLUSTER_ADMIN_KEY"
+ kubeconfigEnvName := "KUBECONFIG"
+
+ err := os.Setenv(defaultClusterBaseURLEnvName, "http://127.0.0.1:8080/apisix")
+ assert.Nil(t, err, "failed to set env variable: ", err)
+ _ = os.Setenv(defaultClusterAdminKeyEnvName, "123456")
+ _ = os.Setenv(kubeconfigEnvName, "")
+
+ jsonData := `
+{
+ "log_level": "warn",
+ "log_output": "stdout",
+ "http_listen": ":9090",
+ "https_listen": ":9443",
+ "enable_profiling": true,
+ "kubernetes": {
+ "kubeconfig": "{{.KUBECONFIG}}",
+ "resync_interval": "1h0m0s",
+ "election_id": "my-election-id",
+ "ingress_class": "apisix",
+ "ingress_version": "networking/v1"
+ },
+ "apisix": {
+ "default_cluster_base_url": "{{.DEFAULT_CLUSTER_BASE_URL}}",
+ "default_cluster_admin_key": "{{.DEFAULT_CLUSTER_ADMIN_KEY}}"
+ }
+}
+`
+ tmpJSON, err := ioutil.TempFile("/tmp", "config-*.json")
+ assert.Nil(t, err, "failed to create temporary json configuration file: ", err)
+ defer os.Remove(tmpJSON.Name())
+
+ _, err = tmpJSON.Write([]byte(jsonData))
+ assert.Nil(t, err, "failed to write json data: ", err)
+ tmpJSON.Close()
+
+ newCfg, err := NewConfigFromFile(tmpJSON.Name())
+ assert.Nil(t, err, "failed to new config from file: ", err)
+ assert.Nil(t, newCfg.Validate(), "failed to validate config")
+
+ assert.Equal(t, cfg, newCfg, "bad configuration")
+
+ yamlData := `
+log_level: warn
+log_output: stdout
+http_listen: :9090
+https_listen: :9443
+enable_profiling: true
+kubernetes:
+ resync_interval: 1h0m0s
+ kubeconfig: "{{.KUBECONFIG}}"
+ election_id: my-election-id
+ ingress_class: apisix
+ ingress_version: networking/v1
+apisix:
+ default_cluster_base_url: {{.DEFAULT_CLUSTER_BASE_URL}}
+ default_cluster_admin_key: "{{.DEFAULT_CLUSTER_ADMIN_KEY}}"
+`
+ tmpYAML, err := ioutil.TempFile("/tmp", "config-*.yaml")
+ assert.Nil(t, err, "failed to create temporary yaml configuration file: ", err)
+ defer os.Remove(tmpYAML.Name())
+
+ _, err = tmpYAML.Write([]byte(yamlData))
+ assert.Nil(t, err, "failed to write yaml data: ", err)
+ tmpYAML.Close()
+
+ newCfg, err = NewConfigFromFile(tmpYAML.Name())
+ assert.Nil(t, err, "failed to new config from file: ", err)
+ assert.Nil(t, newCfg.Validate(), "failed to validate config")
+
+ assert.Equal(t, cfg, newCfg, "bad configuration")
+
+ _ = os.Unsetenv(defaultClusterBaseURLEnvName)
+
+ _, err = NewConfigFromFile(tmpJSON.Name())
+ assert.NotNil(t, err, "should failed because env variable missing")
+
+ _, err = NewConfigFromFile(tmpYAML.Name())
+ assert.NotNil(t, err, "should failed because env variable missing")
+}
+
func TestConfigDefaultValue(t *testing.T) {
yamlData := `
apisix:
diff --git a/test/e2e/config/config.go b/test/e2e/config/config.go
new file mode 100644
index 0000000..51b7a98
--- /dev/null
+++ b/test/e2e/config/config.go
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package config
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+ "github.com/onsi/ginkgo"
+ "github.com/stretchr/testify/assert"
+ v1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+var _ = ginkgo.Describe("deploy ingress controller with config", func() {
+ opts := &scaffold.Options{
+ Name: "default",
+ Kubeconfig: scaffold.GetKubeconfig(),
+ APISIXConfigPath: "testdata/apisix-gw-config.yaml",
+ IngressAPISIXReplicas: 1,
+ HTTPBinServicePort: 80,
+ APISIXRouteVersion: "apisix.apache.org/v2beta2",
+ }
+ s := scaffold.NewScaffold(opts)
+ ginkgo.It("use configmap with env", func() {
+ label := fmt.Sprintf("apisix.ingress.watch=%s", s.Namespace())
+ configMap := fmt.Sprintf(_ingressAPISIXConfigMapTemplate, label)
+ assert.Nil(ginkgo.GinkgoT(), s.CreateResourceFromString(configMap), "create configmap")
+
+ client := s.GetKubernetesClient()
+ deployment, err := client.AppsV1().Deployments(s.Namespace()).Get(context.Background(), "ingress-apisix-controller-deployment-e2e-test", metav1.GetOptions{})
+ assert.Nil(ginkgo.GinkgoT(), err, "get apisix ingress controller deployment")
+
+ spec := &deployment.Spec.Template.Spec
+ spec.Containers[0].Command = []string{
+ "/ingress-apisix/apisix-ingress-controller",
+ "ingress",
+ "--config-path",
+ "/ingress-apisix/conf/config.yaml",
+ }
+ spec.Volumes = append(spec.Volumes, v1.Volume{
+ Name: "apisix-ingress-controller-config",
+ VolumeSource: v1.VolumeSource{
+ ConfigMap: &v1.ConfigMapVolumeSource{
+ LocalObjectReference: v1.LocalObjectReference{
+ Name: "ingress-apisix-controller-config",
+ },
+ },
+ },
+ })
+ spec.Containers[0].VolumeMounts = append(spec.Containers[0].VolumeMounts, v1.VolumeMount{
+ Name: "apisix-ingress-controller-config",
+ MountPath: "/ingress-apisix/conf/config.yaml",
+ SubPath: "config.yaml",
+ })
+ spec.Containers[0].Env = append(spec.Containers[0].Env, v1.EnvVar{
+ Name: "DEFAULT_CLUSTER_BASE_URL",
+ Value: "http://apisix-service-e2e-test:9180/apisix/admin",
+ }, v1.EnvVar{
+ Name: "DEFAULT_CLUSTER_ADMIN_KEY",
+ Value: "edd1c9f034335f136f87ad84b625c8f1",
+ })
+
+ _, err = client.AppsV1().Deployments(s.Namespace()).Update(context.Background(), deployment, metav1.UpdateOptions{})
+ assert.Nil(ginkgo.GinkgoT(), err, "update apisix ingress controller deployment")
+
+ time.Sleep(10 * time.Second)
+ assert.Nil(ginkgo.GinkgoT(), s.WaitAllIngressControllerPodsAvailable(), "wait all ingress controller pod available")
+ })
+})
diff --git a/test/e2e/e2e.go b/test/e2e/config/manifests.go
similarity index 58%
copy from test/e2e/e2e.go
copy to test/e2e/config/manifests.go
index 8c5c597..4010791 100644
--- a/test/e2e/e2e.go
+++ b/test/e2e/config/manifests.go
@@ -12,14 +12,28 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-package e2e
+package config
-import (
- _ "github.com/apache/apisix-ingress-controller/test/e2e/annotations"
- _ "github.com/apache/apisix-ingress-controller/test/e2e/endpoints"
- _ "github.com/apache/apisix-ingress-controller/test/e2e/features"
- _ "github.com/apache/apisix-ingress-controller/test/e2e/ingress"
- _ "github.com/apache/apisix-ingress-controller/test/e2e/plugins"
+const (
+ _ingressAPISIXConfigMapTemplate = `
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: ingress-apisix-controller-config
+data:
+ config.yaml: |
+ apisix:
+ default_cluster_base_url: "{{.DEFAULT_CLUSTER_BASE_URL}}"
+ default_cluster_admin_key: "{{.DEFAULT_CLUSTER_ADMIN_KEY}}"
+ log_level: "debug"
+ log_output: "stdout"
+ http_listen: ":8080"
+ https_listen: ":8443"
+ enable_profiling: true
+ kubernetes:
+ namespace_selector:
+ - %s
+ apisix_route_version: "apisix.apache.org/v2beta2"
+ watch_endpoint_slices: true
+`
)
-
-func runE2E() {}
diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go
index 8c5c597..07cf074 100644
--- a/test/e2e/e2e.go
+++ b/test/e2e/e2e.go
@@ -16,6 +16,7 @@ package e2e
import (
_ "github.com/apache/apisix-ingress-controller/test/e2e/annotations"
+ _ "github.com/apache/apisix-ingress-controller/test/e2e/config"
_ "github.com/apache/apisix-ingress-controller/test/e2e/endpoints"
_ "github.com/apache/apisix-ingress-controller/test/e2e/features"
_ "github.com/apache/apisix-ingress-controller/test/e2e/ingress"
diff --git a/test/e2e/go.mod b/test/e2e/go.mod
index 4c48e5e..643a62b 100644
--- a/test/e2e/go.mod
+++ b/test/e2e/go.mod
@@ -11,6 +11,7 @@ require (
github.com/stretchr/testify v1.7.0
k8s.io/api v0.21.1
k8s.io/apimachinery v0.21.1
+ k8s.io/client-go v0.21.1
)
replace github.com/apache/apisix-ingress-controller => ../../
diff --git a/test/e2e/scaffold/ingress.go b/test/e2e/scaffold/ingress.go
index 8908602..4de7a0c 100644
--- a/test/e2e/scaffold/ingress.go
+++ b/test/e2e/scaffold/ingress.go
@@ -441,7 +441,7 @@ func (s *Scaffold) newIngressAPISIXController() error {
return nil
}
-func (s *Scaffold) waitAllIngressControllerPodsAvailable() error {
+func (s *Scaffold) WaitAllIngressControllerPodsAvailable() error {
opts := metav1.ListOptions{
LabelSelector: "app=ingress-apisix-controller-deployment-e2e-test",
}
diff --git a/test/e2e/scaffold/k8s.go b/test/e2e/scaffold/k8s.go
index 8dbb70c..842c343 100644
--- a/test/e2e/scaffold/k8s.go
+++ b/test/e2e/scaffold/k8s.go
@@ -36,6 +36,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
+ "k8s.io/client-go/kubernetes"
)
type counter struct {
@@ -504,3 +505,10 @@ func (s *Scaffold) EnsureNumEndpointsReady(t testing.TestingT, endpointsName str
)
ginkgo.GinkgoT().Log(message)
}
+
+// GetKubernetesClient get kubernetes client use by scaffold
+func (s *Scaffold) GetKubernetesClient() *kubernetes.Clientset {
+ client, err := k8s.GetKubernetesClientFromOptionsE(s.t, s.kubectlOptions)
+ assert.Nil(ginkgo.GinkgoT(), err, "get kubernetes client")
+ return client
+}
diff --git a/test/e2e/scaffold/scaffold.go b/test/e2e/scaffold/scaffold.go
index a330c86..2007a9d 100644
--- a/test/e2e/scaffold/scaffold.go
+++ b/test/e2e/scaffold/scaffold.go
@@ -324,7 +324,7 @@ func (s *Scaffold) beforeEach() {
err = s.newIngressAPISIXController()
assert.Nil(s.t, err, "initializing ingress apisix controller")
- err = s.waitAllIngressControllerPodsAvailable()
+ err = s.WaitAllIngressControllerPodsAvailable()
assert.Nil(s.t, err, "waiting for ingress apisix controller ready")
}