add production certificate issuer and fix route trait

This commit is contained in:
天元
2020-09-17 20:01:21 +08:00
parent 2ffd56a993
commit 3af41f6515
18 changed files with 306 additions and 163 deletions

View File

@@ -5,12 +5,10 @@ contributing to `kubevela` or build a PoC (Proof of Concept).
## Prerequisites
1. Golang version 1.12+
2. Kubernetes version v1.15+ with `~/.kube/config` configured.
3. OAM Kubernetes Runtime installed.
4. Kustomize version 3.8+
5. ginkgo 1.14.0+ (just for [E2E test](https://github.com/oam-dev/kubevela/blob/master/DEVELOPMENT.md#e2e-test))
6. golangci-lint 1.31.0+, it will install automatically if you run `make`, you can [install it manually](https://golangci-lint.run/usage/install/#local-installation) if the installation is too slow.
1. Golang version 1.13+
2. Kubernetes version v1.16+ with `~/.kube/config` configured.
3. ginkgo 1.14.0+ (just for [E2E test](https://github.com/oam-dev/kubevela/blob/master/DEVELOPMENT.md#e2e-test))
4. golangci-lint 1.31.0+, it will install automatically if you run `make`, you can [install it manually](https://golangci-lint.run/usage/install/#local-installation) if the installation is too slow.
## Build
* Clone this project
@@ -19,96 +17,89 @@ contributing to `kubevela` or build a PoC (Proof of Concept).
git clone git@github.com:oam-dev/kubevela.git
```
* Install Template CRD into your cluster
* Build Vela CLI
```shell script
make install
make
```
* Install template object
* Configure vela to PATH
after build, make will create `vela` binary to `bin/`, Set this path to PATH.
```shell script
kubectl apply -f config/samples/
export PATH=$PATH:/your/path/to/project/kubevela/bin
```
## Develop & Debug
If you change Template CRD, remember to rerun `make install`.
Use the following command to develop and debug.
* Install Vela Core
```shell script
$ cd cmd/vela
$ go run main.go COMMAND [FLAG]
vela install
```
## Use
* Create ENV
```shell script
vela env init myenv --namespace myenv --email my@email.com --domain kubevela.io
```
* Create Component
For example, use the following command to create and run an application.
```shell script
$ go run main.go run containerized app2057 nginx:1.9.4
Creating AppConfig app2057
$ vela comp run mycomp -t webservice --image crccheck/hello-world --port 8000
Creating AppConfig appcomp
SUCCEED
$ kubectl get oam
NAME WORKLOAD-KIND
component.core.oam.dev/app2057 ContainerizedWorkload
NAME AGE
containerizedworkload.core.oam.dev/poc 53m
NAME AGE
applicationconfiguration.core.oam.dev/app2057 69s
NAME DEFINITION-NAME
traitdefinition.core.oam.dev/simplerollouttraits.extend.oam.dev simplerollouttraits.extend.oam.dev
NAME DEFINITION-NAME
workloaddefinition.core.oam.dev/containerizedworkloads.core.oam.dev containerizedworkloads.core.oam.dev
workloaddefinition.core.oam.dev/deployments.apps deployments.apps
workloaddefinition.core.oam.dev/statefulsets.apps statefulsets.apps
```
## E2E test
```
$ make e2e-test
Running Suite: Trait Suite
==========================
Random Seed: 1596559178
Will run 5 of 5 specs
* Add Trait
Trait env init
should print env initiation successful message
kubevela/e2e/commonContext.go:14
Create env succeed, current env is default
------------------------------
Trait env set
should show env set message
kubevela/e2e/commonContext.go:40
Set env succeed, current env is default
------------------------------
Trait run
should print successful creation information
kubevela/e2e/commonContext.go:76
Creating AppConfig app-trait-basic
SUCCEED
------------------------------
Trait kubevela attach trait
should print successful attached information
kubevela/e2e/trait/trait_test.go:24
Applying trait for app
```shell script
$ vela route mycomp
Adding route for app abc
Succeeded!
------------------------------
Trait delete
should print successful deletion information
kubevela/e2e/commonContext.go:85
Deleting AppConfig "app-trait-basic"
DELETE SUCCEED
Ran 5 of 5 Specs in 9.717 seconds
SUCCESS! -- 5 Passed | 0 Failed | 0 Pending | 0 Skipped
PASS
```
* Check Status
```
$ vela comp status abc
Showing status of Component abc deployed in Environment t2
Component Status:
Name: abc Containerized(type) UNKNOWN APIVersion standard.oam.dev/v1alpha1 Kind Containerized workload is unknown for HealthScope
Traits
└─Trait/route
Last Deployment:
Created at: 2020-09-18 18:47:09 +0800 CST
Updated at: 2020-09-18T18:47:16+08:00
```
* Delete App
```shell script
$ vela app ls
abc
$ vela app delete abc
Deleting Application "abc"
delete apps succeed abc from t2
```
## Tests
### Unit test
```shell script
make test
```
### E2E test
```
make e2e-test
```
## Make a pull request

View File

@@ -29,38 +29,54 @@ This command will install vela core controller into your K8s cluster, along with
## Demos
#### Check workloads
```
$ vela workloads
NAME DEFINITION
backend containerizeds.standard.oam.dev
task jobs
webservice containerizeds.standard.oam.dev
```
#### workload run
* Create ENV
```shell script
$ vela comp run -t webservice app123 -p 80 --image nginx:1.9.4
Creating AppConfig app123
vela env init myenv --namespace myenv --email my@email.com --domain kubevela.io
```
* Create Component
For example, use the following command to create and run an application.
```shell script
$ vela comp run mycomp -t webservice --image crccheck/hello-world --port 8000
Creating AppConfig appcomp
SUCCEED
$ vela comp status app123
$ vela comp ls
NAME APP WORKLOAD TRAITS STATUS CREATED-TIME
app123 app123 deployment Deployed 2020-08-27 10:56:41 +0800 CST
```
#### app
* Add Trait
```shell script
$ vela route mycomp
Adding route for app abc
Succeeded!
```
* Check Status
```
$ vela comp status abc
Showing status of Component abc deployed in Environment t2
Component Status:
Name: abc Containerized(type) UNKNOWN APIVersion standard.oam.dev/v1alpha1 Kind Containerized workload is unknown for HealthScope
Traits
└─Trait/route
Last Deployment:
Created at: 2020-09-18 18:47:09 +0800 CST
Updated at: 2020-09-18T18:47:16+08:00
```
* Delete App
```shell script
$ vela app ls
app123
abc
$ vela app delete app123
Deleting AppConfig "app123"
DELETE SUCCEED
$ vela app delete abc
Deleting Application "abc"
delete apps succeed abc from t2
```
#### Auto-Completion

View File

@@ -27,8 +27,13 @@ const (
type EnvMeta struct {
Name string `json:"name"`
Current string `json:"current,omitempty"`
Namespace string `json:"namespace"`
Email string `json:"email,omitempty"`
Domain string `json:"domain,omitempty"`
// Below are not arguments, should be auto-generated
Issuer string `json:"issuer"`
Current string `json:"current,omitempty"`
}
const (

View File

@@ -0,0 +1,37 @@
apiVersion: core.oam.dev/v1alpha2
kind: TraitDefinition
metadata:
name: routes.standard.oam.dev
annotations:
definition.oam.dev/apiVersion: standard.oam.dev/v1alpha1
definition.oam.dev/kind: Route
spec:
appliesToWorkloads:
- core.oam.dev/v1alpha2.ContainerizedWorkload
- standard.oam.dev/v1alpha1.Containerized
- deployments.apps
workloadRefPath: spec.workloadRef
definitionRef:
name: routes.standard.oam.dev
extension:
template: |
#Template: {
apiVersion: "standard.oam.dev/v1alpha1"
kind: "Route"
spec: {
host: route.domain
path: route.path
tls: {
issuerName: route.issuer
}
backend: {
port: route.port
}
}
}
route: {
domain: *"" | string
path: *"" | string
port: *443 | int
issuer: *"" | string
}

View File

@@ -17,6 +17,7 @@ import (
"github.com/crossplane/oam-kubernetes-runtime/apis/core"
"github.com/gosuri/uitable"
certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
"github.com/spf13/cobra"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
@@ -34,7 +35,7 @@ var chartTGZSource string
func init() {
_ = clientgoscheme.AddToScheme(scheme)
_ = certmanager.AddToScheme(scheme)
_ = core.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme
}

View File

@@ -0,0 +1,19 @@
apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# You must replace this email address with your own.
# Let's Encrypt will use this to contact you about expiring
# certificates, and issues related to your account.
email: wonderflow@icloud.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
# Secret resource that will be used to store the account's private key.
name: example-issuer-account-key
# Add a single challenge solver, HTTP01 using nginx
solvers:
- http01:
ingress:
class: nginx

View File

@@ -21,13 +21,17 @@ spec:
spec: {
host: route.domain
path: route.path
tls: {
issuerName: route.issuer
}
backend: {
port: route.port
}
}
}
route: {
domain: string
domain: *"" | string
path: *"" | string
port: *443 | int
issuer: *"" | string
}

View File

@@ -58,7 +58,7 @@ var (
cli := fmt.Sprintf("vela env init %s --namespace %s", envName, envName)
output, err := Exec(cli)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
expectedOutput := fmt.Sprintf("Create env succeed, current env is %s", envName)
expectedOutput := fmt.Sprintf("ENV %s CREATED,", envName)
gomega.Expect(output).To(gomega.ContainSubstring(expectedOutput))
})
})
@@ -214,7 +214,7 @@ var (
err = json.Unmarshal(result, &r)
gomega.Expect(err).NotTo(gomega.HaveOccurred())
gomega.Expect(http.StatusOK).Should(gomega.Equal(r.Code))
gomega.Expect(r.Data.(string)).To(gomega.ContainSubstring("Create env succeed"))
gomega.Expect(r.Data.(string)).To(gomega.ContainSubstring("CREATED"))
})
})
}

View File

@@ -320,7 +320,7 @@ func EvalToObject(capName string, data map[string]interface{}) (*unstructured.Un
return u, nil
}
func (app *Application) GetComponentTraits(componentName string) ([]v1alpha2.ComponentTrait, error) {
func (app *Application) GetComponentTraits(componentName string, env *types.EnvMeta) ([]v1alpha2.ComponentTrait, error) {
var traits []v1alpha2.ComponentTrait
rawTraits, err := app.GetTraits(componentName)
if err != nil {
@@ -338,6 +338,14 @@ func (app *Application) GetComponentTraits(componentName string) ([]v1alpha2.Com
return traits, nil
}
func (app *Application) VelaCoreInjection(obj *unstructured.Unstructured, env *types.EnvMeta, traitType string) {
switch traitType {
case "route":
}
}
func FormatDefaultHealthScopeName(appName string) string {
return appName + "-default-health"
}
@@ -387,7 +395,7 @@ func (app *Application) OAM(env *types.EnvMeta) ([]v1alpha2.Component, v1alpha2.
}})
//TODO(wonderflow): handle component data input/output here
compTraits, err := app.GetComponentTraits(name)
compTraits, err := app.GetComponentTraits(name, env)
if err != nil {
return nil, v1alpha2.ApplicationConfiguration{}, nil, err
}

View File

@@ -57,7 +57,7 @@ func NewEnvInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
DisableFlagsInUseLine: true,
Short: "Create environments",
Long: "Create environment and set the currently using environment",
Example: `vela env init test --namespace test`,
Example: `vela env init test --namespace test --email my@email.com`,
RunE: func(cmd *cobra.Command, args []string) error {
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
if err != nil {
@@ -71,6 +71,8 @@ func NewEnvInitCommand(c types.Args, ioStreams cmdutil.IOStreams) *cobra.Command
}
cmd.SetOut(ioStreams.Out)
cmd.Flags().StringVar(&envArgs.Namespace, "namespace", "default", "specify K8s namespace for env")
cmd.Flags().StringVar(&envArgs.Email, "email", "", "specify email for production TLS Certificate notification")
cmd.Flags().StringVar(&envArgs.Domain, "domain", "", "specify domain your applications")
return cmd
}
@@ -94,7 +96,6 @@ func NewEnvDeleteCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
}
func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
ctx := context.Background()
cmd := &cobra.Command{
Use: "set",
Aliases: []string{"sw"},
@@ -103,7 +104,7 @@ func NewEnvSetCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
Long: "Set an environment as the current using one",
Example: `vela env set test`,
RunE: func(cmd *cobra.Command, args []string) error {
return SetEnv(ctx, args, ioStreams)
return SetEnv(args, ioStreams)
},
Annotations: map[string]string{
types.TagCommandType: types.TypeStart,
@@ -149,8 +150,8 @@ func CreateOrUpdateEnv(ctx context.Context, c client.Client, envArgs *types.EnvM
return fmt.Errorf("you must specify env name for vela env init command")
}
envName := args[0]
namespace := envArgs.Namespace
msg, err := oam.CreateOrUpdateEnv(ctx, c, envName, namespace)
envArgs.Name = envName
msg, err := oam.CreateOrUpdateEnv(ctx, c, envName, envArgs)
if err != nil {
return err
}
@@ -158,7 +159,7 @@ func CreateOrUpdateEnv(ctx context.Context, c client.Client, envArgs *types.EnvM
return nil
}
func SetEnv(ctx context.Context, args []string, ioStreams cmdutil.IOStreams) error {
func SetEnv(args []string, ioStreams cmdutil.IOStreams) error {
if len(args) < 1 {
return fmt.Errorf("you must specify env name for vela env command")
}

View File

@@ -77,7 +77,7 @@ func TestENV(t *testing.T) {
assert.Error(t, err)
// set as default env
err = SetEnv(ctx, []string{"default"}, ioStream)
err = SetEnv([]string{"default"}, ioStream)
assert.NoError(t, err)
// check env set success
@@ -93,10 +93,10 @@ func TestENV(t *testing.T) {
assert.NoError(t, err)
// can not set as a non-exist env
err = SetEnv(ctx, []string{"env1"}, ioStream)
err = SetEnv([]string{"env1"}, ioStream)
assert.Error(t, err)
// set success
err = SetEnv(ctx, []string{"default"}, ioStream)
err = SetEnv([]string{"default"}, ioStream)
assert.NoError(t, err)
}

View File

@@ -44,7 +44,7 @@ func AddTraitCommands(parentCmd *cobra.Command, c types.Args, ioStreams cmdutil.
Long: "Attach " + name + " trait to an app",
Example: "vela " + name + " frontend",
RunE: func(cmd *cobra.Command, args []string) error {
o := &commandOptions{IOStreams: ioStreams}
o := &commandOptions{IOStreams: ioStreams, traitType: name}
o.Template = tmp
newClient, err := client.New(c.Config, client.Options{Scheme: c.Schema})
if err != nil {
@@ -103,7 +103,9 @@ func (o *commandOptions) AddOrUpdateTrait(cmd *cobra.Command, args []string) err
if err = o.Prepare(cmd, args); err != nil {
return err
}
if o.app, err = oam.AddOrUpdateTrait(o.Env.Name, o.appName, o.workloadName, cmd.Flags(), o.Template); err != nil {
flags := cmd.Flags()
if o.app, err = oam.AddOrUpdateTrait(o.Env, o.appName, o.workloadName, flags, o.Template); err != nil {
return err
}
return nil
@@ -138,6 +140,7 @@ func (o *commandOptions) Run(ctx context.Context, cmd *cobra.Command) error {
if err != nil {
return err
}
o.Info(msg)
return nil
}

View File

@@ -201,7 +201,7 @@ func (r *Reconciler) createService(ctx context.Context, mLog logr.Logger, worklo
},
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
Type: corev1.ServiceTypeClusterIP,
},
}
// assign selector

View File

@@ -9,6 +9,9 @@ import (
"os"
"path/filepath"
"github.com/jetstack/cert-manager/pkg/apis/acme/v1alpha2"
certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
v1 "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -36,15 +39,40 @@ func GetEnvByName(name string) (*types.EnvMeta, error) {
//Create or update env.
//If it does not exist, create it and set to the new env.
//If it exists, update it and set to the new env.
func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, namespace string) (string, error) {
func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) {
var message = ""
var envArgs = types.EnvMeta{
Name: envName,
Namespace: namespace,
}
// Create Namespace
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil && !apierrors.IsAlreadyExists(err) {
return message, err
}
// Create Issuer For SSL
if envArgs.Email != "" {
issuerName := "oam-env-" + envArgs.Name
if err := c.Create(ctx, &certmanager.Issuer{
ObjectMeta: metav1.ObjectMeta{Name: issuerName, Namespace: envArgs.Namespace},
Spec: certmanager.IssuerSpec{
IssuerConfig: certmanager.IssuerConfig{
ACME: &v1alpha2.ACMEIssuer{
Email: envArgs.Email,
Server: "https://acme-v02.api.letsencrypt.org/directory",
PrivateKey: v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{Name: "oam-env-" + envArgs.Name + ".key"},
},
Solvers: []v1alpha2.ACMEChallengeSolver{{
HTTP01: &v1alpha2.ACMEChallengeSolverHTTP01{
Ingress: &v1alpha2.ACMEChallengeSolverHTTP01Ingress{Class: GetStringPointer("nginx")},
},
}},
},
},
},
}); err != nil && !apierrors.IsAlreadyExists(err) {
return message, err
}
envArgs.Issuer = issuerName
}
data, err := json.Marshal(envArgs)
if err != nil {
return message, err
@@ -67,42 +95,22 @@ func CreateOrUpdateEnv(ctx context.Context, c client.Client, envName string, nam
if err = ioutil.WriteFile(curEnvPath, []byte(envName), 0644); err != nil {
return message, err
}
message = fmt.Sprintf("Create env succeed, current env is " + envName + " namespace is " + envArgs.Namespace + ", use --namespace=<namespace> to specify namespace with env init")
message = fmt.Sprintf("ENV %s CREATED, Namespace: %s, Email: %s.", envName, envArgs.Namespace, envArgs.Email)
return message, nil
}
//Create env. If env already exists, return error
func CreateEnv(ctx context.Context, c client.Client, envName string, namespace string) (string, error) {
var message = ""
var envArgs = types.EnvMeta{
Name: envName,
Namespace: namespace,
}
data, err := json.Marshal(envArgs)
if err != nil {
return message, err
}
_, err = GetEnvByName(envName)
func GetStringPointer(v string) *string {
return &v
}
// CreateEnv will only create. If env already exists, return error
func CreateEnv(ctx context.Context, c client.Client, envName string, envArgs *types.EnvMeta) (string, error) {
_, err := GetEnvByName(envName)
if err == nil {
message = fmt.Sprintf("Env %s already exist", envName)
message := fmt.Sprintf("Env %s already exist", envName)
return message, errors.New(message)
}
if err := c.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: envArgs.Namespace}}); err != nil && !apierrors.IsAlreadyExists(err) {
return message, err
}
envdir, err := system.GetEnvDir()
if err != nil {
return message, err
}
subEnvDir := filepath.Join(envdir, envName)
if _, err := system.CreateIfNotExist(subEnvDir); err != nil {
return "", nil
}
if err = ioutil.WriteFile(filepath.Join(subEnvDir, system.EnvConfigName), data, 0644); err != nil {
return message, err
}
message = "Create env succeed"
return message, err
return CreateOrUpdateEnv(ctx, c, envName, envArgs)
}
//Update Env, if env does not exist, return error

View File

@@ -148,12 +148,47 @@ func SimplifyCapabilityStruct(capabilityList []types.Capability) []apis.TraitMet
return traitList
}
func ValidateAndMutateForCore(traitType, workloadName string, flags *pflag.FlagSet, env *types.EnvMeta) error {
switch traitType {
case "route":
domain, _ := flags.GetString("domain")
if domain == "" {
if env.Domain == "" {
return fmt.Errorf("--domain is required if not set in env")
}
if strings.HasPrefix(env.Domain, "https://") {
env.Domain = strings.TrimPrefix(env.Domain, "https://")
}
if strings.HasPrefix(env.Domain, "http://") {
env.Domain = strings.TrimPrefix(env.Domain, "http://")
}
if err := flags.Set("domain", workloadName+"."+env.Domain); err != nil {
return fmt.Errorf("set flag for vela-core trait('route') err %v, please make sure your template is right", err)
}
}
issuer, _ := flags.GetString("issuer")
if issuer == "" {
if env.Issuer == "" {
return fmt.Errorf("--issuer is required, you can also set email in env and let it generate automatically")
}
if err := flags.Set("issuer", env.Issuer); err != nil {
return fmt.Errorf("set flag for vela-core trait('route') err %v, please make sure your template is right", err)
}
}
}
return nil
}
//AddOrUpdateTrait attach trait to workload
func AddOrUpdateTrait(envName string, appName string, workloadName string, flagSet *pflag.FlagSet, template types.Capability) (*application.Application, error) {
func AddOrUpdateTrait(env *types.EnvMeta, appName string, workloadName string, flagSet *pflag.FlagSet, template types.Capability) (*application.Application, error) {
err := ValidateAndMutateForCore(template.Name, workloadName, flagSet, env)
if err != nil {
return nil, err
}
if appName == "" {
appName = workloadName
}
app, err := application.Load(envName, appName)
app, err := application.Load(env.Name, appName)
if err != nil {
return app, err
}
@@ -181,7 +216,7 @@ func AddOrUpdateTrait(envName string, appName string, workloadName string, flagS
if err = app.SetTrait(workloadName, traitAlias, traitData); err != nil {
return app, err
}
return app, app.Save(envName)
return app, app.Save(env.Name)
}
func AttachTrait(c *gin.Context, body apis.TraitBody) (string, error) {
@@ -204,12 +239,13 @@ func AttachTrait(c *gin.Context, body apis.TraitBody) (string, error) {
if err != nil {
return "", err
}
appObj, err = AddOrUpdateTrait(body.EnvName, body.AppGroup, body.WorkloadName, fs, template)
// Run step
env, err := GetEnvByName(body.EnvName)
if err != nil {
return "", err
}
// Run step
env, err := GetEnvByName(body.EnvName)
appObj, err = AddOrUpdateTrait(env, body.AppGroup, body.WorkloadName, fs, template)
if err != nil {
return "", err
}

View File

@@ -10,6 +10,8 @@ import (
type Environment struct {
EnvName string `json:"envName" binding:"required,min=1,max=32"`
Namespace string `json:"namespace" binding:"required,min=1,max=32"`
Email string `json:"email"`
Domain string `json:"domain"`
Current string `json:"current,omitempty"`
}

View File

@@ -2,6 +2,7 @@ package handler
import (
"github.com/gin-gonic/gin"
"github.com/oam-dev/kubevela/api/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -23,9 +24,16 @@ func CreateEnv(c *gin.Context) {
if namespace == "" {
namespace = "default"
}
ctx := util.GetContext(c)
kubeClient := c.MustGet("KubeClient")
message, err := oam.CreateEnv(ctx, kubeClient.(client.Client), name, namespace)
message, err := oam.CreateEnv(ctx, kubeClient.(client.Client), name, &types.EnvMeta{
Name: name,
Current: environment.Current,
Namespace: namespace,
Email: environment.Email,
Domain: environment.Domain,
})
util.AssembleResponse(c, message, err)
}

View File

@@ -4,13 +4,17 @@
spec: {
host: route.domain
path: route.path
tls: {
issuerName: route.issuer
}
backend: {
port: route.port
}
}
}
route: {
domain: string
domain: *"" | string
path: *"" | string
port: *443 | int
issuer: *"" | string
}