kubevela/pkg/utils/common/common.go

507 lines
16 KiB
Go
Raw Normal View History

/*
Copyright 2021 The KubeVela Authors.
Licensed 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 common
import (
"bytes"
2020-11-18 16:08:16 +08:00
"context"
"encoding/json"
"errors"
"fmt"
"io"
2020-11-18 16:08:16 +08:00
"net/http"
"os"
"os/exec"
"path/filepath"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/format"
"cuelang.org/go/encoding/openapi"
"github.com/AlecAivazis/survey/v2"
"github.com/hashicorp/hcl/v2/hclparse"
clustergatewayapi "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1"
"github.com/oam-dev/terraform-config-inspect/tfconfig"
terraformv1beta1 "github.com/oam-dev/terraform-controller/api/v1beta1"
kruise "github.com/openkruise/kruise-api/apps/v1alpha1"
errors2 "github.com/pkg/errors"
certmanager "github.com/wonderflow/cert-manager-api/pkg/apis/certmanager/v1"
istioclientv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
Refactor: align velaux env and CLI env, they both use K8s namespace as (#2975) * Refactor: use createOrUpdateNamespace as a common util function Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add ENV webservice handelr * Fix: fix Env usecase logic * Feat: Add Delete Env API Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: filter empty addon data Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: split makefiels and make it clear * Feat: add k8s utils test * Feat: Add env update interface Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: change env implementation Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: minor fix * Revert "Fix: minor fix" This reverts commit 9cafefa65a384795315924cb18e48681dd7086a1. * Fix: use appusecase as parameter Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Refactor: align CLI vela env with new env design Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: minor fix Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add page index and alias of env Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix tests and licence header * Fix: fix makefile and add default target Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update build swagger.json Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: change update env api Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: list env with alias * Feat: add log to env delete * Fix: can not get app status Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support update workflow and refactor code * Fix: lint * Fix: remove swagger check Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix cli vela delete * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: app deploy unit test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: SortOrderDescending is not effective Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support default project/target/env * Fix: make test and add swagger * Fix: use separated datasource for unit test * Fix: app rollback bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: fix e2e test * Fix: kubeapi driver sort bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test fix * Fix: try fix e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-25 10:36:54 +08:00
v1 "k8s.io/api/core/v1"
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/util/flowcontrol"
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
ocmclusterv1 "open-cluster-management.io/api/cluster/v1"
2021-08-06 10:46:31 +08:00
ocmclusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
ocmworkv1 "open-cluster-management.io/api/work/v1"
2021-08-11 23:05:10 +08:00
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/yaml"
oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
oamstandard "github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/apis/types"
velacue "github.com/oam-dev/kubevela/pkg/cue"
"github.com/oam-dev/kubevela/pkg/cue/model"
Refactor: align velaux env and CLI env, they both use K8s namespace as (#2975) * Refactor: use createOrUpdateNamespace as a common util function Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add ENV webservice handelr * Fix: fix Env usecase logic * Feat: Add Delete Env API Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: filter empty addon data Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: split makefiels and make it clear * Feat: add k8s utils test * Feat: Add env update interface Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: change env implementation Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: minor fix * Revert "Fix: minor fix" This reverts commit 9cafefa65a384795315924cb18e48681dd7086a1. * Fix: use appusecase as parameter Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Refactor: align CLI vela env with new env design Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: minor fix Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add page index and alias of env Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix tests and licence header * Fix: fix makefile and add default target Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update build swagger.json Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: change update env api Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: list env with alias * Feat: add log to env delete * Fix: can not get app status Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support update workflow and refactor code * Fix: lint * Fix: remove swagger check Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix cli vela delete * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: app deploy unit test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: SortOrderDescending is not effective Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support default project/target/env * Fix: make test and add swagger * Fix: use separated datasource for unit test * Fix: app rollback bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: fix e2e test * Fix: kubeapi driver sort bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test fix * Fix: try fix e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-25 10:36:54 +08:00
"github.com/oam-dev/kubevela/pkg/oam"
)
var (
// Scheme defines the default KubeVela schema
Scheme = k8sruntime.NewScheme()
)
const (
// AddonObservabilityApplication is the application name for Addon Observability
AddonObservabilityApplication = "addon-observability"
// AddonObservabilityGrafanaSvc is grafana service name for Addon Observability
AddonObservabilityGrafanaSvc = "grafana"
)
Refactor: align velaux env and CLI env, they both use K8s namespace as (#2975) * Refactor: use createOrUpdateNamespace as a common util function Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add ENV webservice handelr * Fix: fix Env usecase logic * Feat: Add Delete Env API Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: filter empty addon data Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: split makefiels and make it clear * Feat: add k8s utils test * Feat: Add env update interface Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: change env implementation Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: minor fix * Revert "Fix: minor fix" This reverts commit 9cafefa65a384795315924cb18e48681dd7086a1. * Fix: use appusecase as parameter Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Refactor: align CLI vela env with new env design Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: minor fix Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add page index and alias of env Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix tests and licence header * Fix: fix makefile and add default target Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update build swagger.json Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: change update env api Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: list env with alias * Feat: add log to env delete * Fix: can not get app status Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support update workflow and refactor code * Fix: lint * Fix: remove swagger check Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix cli vela delete * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: app deploy unit test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: SortOrderDescending is not effective Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support default project/target/env * Fix: make test and add swagger * Fix: use separated datasource for unit test * Fix: app rollback bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: fix e2e test * Fix: kubeapi driver sort bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test fix * Fix: try fix e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-25 10:36:54 +08:00
// CreateCustomNamespace display the create namespace message
const CreateCustomNamespace = "create new namespace"
func init() {
_ = clientgoscheme.AddToScheme(Scheme)
_ = apiregistrationv1.AddToScheme(Scheme)
_ = crdv1.AddToScheme(Scheme)
_ = oamcore.AddToScheme(Scheme)
_ = oamstandard.AddToScheme(Scheme)
_ = istioclientv1beta1.AddToScheme(Scheme)
_ = certmanager.AddToScheme(Scheme)
_ = kruise.AddToScheme(Scheme)
_ = terraformv1beta1.AddToScheme(Scheme)
2021-08-06 10:46:31 +08:00
_ = ocmclusterv1alpha1.Install(Scheme)
_ = ocmclusterv1.Install(Scheme)
2021-08-06 10:46:31 +08:00
_ = ocmworkv1.Install(Scheme)
_ = clustergatewayapi.AddToScheme(Scheme)
// +kubebuilder:scaffold:scheme
}
// InitBaseRestConfig will return reset config for create controller runtime client
func InitBaseRestConfig() (Args, error) {
restConf, err := config.GetConfig()
if err != nil && os.Getenv("IGNORE_KUBE_CONFIG") != "true" {
fmt.Println("get kubeConfig err", err)
os.Exit(1)
} else if err != nil {
return Args{}, err
}
restConf.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(100, 200)
return Args{
Config: restConf,
Schema: Scheme,
}, nil
}
2020-11-18 16:08:16 +08:00
// globalClient will be a client for whole command lifecycle
var globalClient client.Client
// SetGlobalClient will set a client for one cli command
func SetGlobalClient(clt client.Client) error {
globalClient = clt
return nil
}
// GetClient will K8s client in args
func GetClient() (client.Client, error) {
if globalClient != nil {
return globalClient, nil
}
return nil, errors.New("client not set, call SetGlobalClient first")
}
2020-11-18 16:08:16 +08:00
// HTTPGet will send GET http request with context
func HTTPGet(ctx context.Context, url string) ([]byte, error) {
// Change NewRequest to NewRequestWithContext and pass context it
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
//nolint:errcheck
defer resp.Body.Close()
return io.ReadAll(resp.Body)
2020-11-18 16:08:16 +08:00
}
// GetCUEParameterValue converts definitions to cue format
func GetCUEParameterValue(cueStr string) (cue.Value, error) {
r := cue.Runtime{}
template, err := r.Compile("", cueStr+velacue.BaseTemplate)
if err != nil {
return cue.Value{}, err
}
tempStruct, err := template.Value().Struct()
if err != nil {
return cue.Value{}, err
}
// find the parameter definition
var paraDef cue.FieldInfo
var found bool
for i := 0; i < tempStruct.Len(); i++ {
paraDef = tempStruct.Field(i)
if paraDef.Name == model.ParameterFieldName {
found = true
break
}
}
if !found {
return cue.Value{}, errors.New("parameter not exist")
}
arguments := paraDef.Value
return arguments, nil
}
// GenOpenAPI generates OpenAPI json schema from cue.Instance
func GenOpenAPI(inst *cue.Instance) ([]byte, error) {
if inst.Err != nil {
return nil, inst.Err
}
paramOnlyIns, err := RefineParameterInstance(inst)
if err != nil {
return nil, err
}
defaultConfig := &openapi.Config{}
b, err := openapi.Gen(paramOnlyIns, defaultConfig)
if err != nil {
return nil, err
}
var out = &bytes.Buffer{}
_ = json.Indent(out, b, "", " ")
return out.Bytes(), nil
}
// extractParameterDefinitionNodeFromInstance extracts the `#parameter` ast.Node from root instance, if failed fall back to `parameter` by LookUpDef
func extractParameterDefinitionNodeFromInstance(inst *cue.Instance) ast.Node {
opts := []cue.Option{cue.All(), cue.DisallowCycles(true), cue.ResolveReferences(true), cue.Docs(true)}
node := inst.Value().Syntax(opts...)
if fileNode, ok := node.(*ast.File); ok {
for _, decl := range fileNode.Decls {
if field, ok := decl.(*ast.Field); ok {
if label, ok := field.Label.(*ast.Ident); ok && label.Name == "#"+model.ParameterFieldName {
return decl.(*ast.Field).Value
}
}
}
}
paramVal := inst.LookupDef(model.ParameterFieldName)
return paramVal.Syntax(opts...)
}
// RefineParameterInstance refines cue instance to merely include `parameter` identifier
func RefineParameterInstance(inst *cue.Instance) (*cue.Instance, error) {
r := cue.Runtime{}
paramVal := inst.LookupDef(model.ParameterFieldName)
var paramOnlyStr string
switch k := paramVal.IncompleteKind(); k {
case cue.StructKind, cue.ListKind:
paramSyntax, _ := format.Node(extractParameterDefinitionNodeFromInstance(inst))
paramOnlyStr = fmt.Sprintf("#%s: %s\n", model.ParameterFieldName, string(paramSyntax))
case cue.IntKind, cue.StringKind, cue.FloatKind, cue.BoolKind:
paramOnlyStr = fmt.Sprintf("#%s: %v", model.ParameterFieldName, paramVal)
case cue.BottomKind:
paramOnlyStr = fmt.Sprintf("#%s: {}", model.ParameterFieldName)
default:
return nil, fmt.Errorf("unsupport parameter kind: %s", k.String())
}
paramOnlyIns, err := r.Compile("-", paramOnlyStr)
if err != nil {
return nil, err
}
return paramOnlyIns, nil
}
// RealtimePrintCommandOutput prints command output in real time
// If logFile is "", it will prints the stdout, or it will write to local file
func RealtimePrintCommandOutput(cmd *exec.Cmd, logFile string) error {
var writer io.Writer
if logFile == "" {
writer = io.MultiWriter(os.Stdout)
} else {
if _, err := os.Stat(filepath.Dir(logFile)); err != nil {
return err
}
f, err := os.Create(filepath.Clean(logFile))
if err != nil {
return err
}
writer = io.MultiWriter(f)
}
cmd.Stdout = writer
cmd.Stderr = writer
if err := cmd.Run(); err != nil {
return err
}
return nil
}
// ClusterObject2Map convert ClusterObjectReference to a readable map
func ClusterObject2Map(refs []common.ClusterObjectReference) map[string]string {
clusterResourceRefTmpl := "Cluster: %s | Namespace: %s | Component: %s | Kind: %s"
objs := make(map[string]string, len(refs))
for _, r := range refs {
if r.Cluster == "" {
r.Cluster = "local"
}
objs[r.Cluster+"/"+r.Namespace+"/"+r.Name+"/"+r.Kind] = fmt.Sprintf(clusterResourceRefTmpl, r.Cluster, r.Namespace, r.Name, r.Kind)
}
return objs
}
// ResourceLocation indicates the resource location
type ResourceLocation struct {
Cluster string
Namespace string
}
type clusterObjectReferenceFilter func(common.ClusterObjectReference) bool
func clusterObjectReferenceTypeFilterGenerator(allowedKinds ...string) clusterObjectReferenceFilter {
allowedKindMap := map[string]bool{}
for _, allowedKind := range allowedKinds {
allowedKindMap[allowedKind] = true
}
return func(item common.ClusterObjectReference) bool {
_, exists := allowedKindMap[item.Kind]
return exists
}
}
var isWorkloadClusterObjectReferenceFilter = clusterObjectReferenceTypeFilterGenerator("Deployment", "StatefulSet", "CloneSet", "Job", "Configuration")
var isPortForwardEndpointClusterObjectReferenceFilter = clusterObjectReferenceTypeFilterGenerator("Deployment",
"StatefulSet", "CloneSet", "Job", "Service", "HelmRelease")
func filterResource(inputs []common.ClusterObjectReference, filters ...clusterObjectReferenceFilter) (outputs []common.ClusterObjectReference) {
for _, item := range inputs {
flag := true
for _, filter := range filters {
if !filter(item) {
flag = false
break
}
}
if flag {
outputs = append(outputs, item)
}
}
return
}
func askToChooseOneResource(app *v1beta1.Application, filters ...clusterObjectReferenceFilter) (*common.ClusterObjectReference, error) {
resources := app.Status.AppliedResources
if len(resources) == 0 {
return nil, fmt.Errorf("no resources in the application deployed yet")
}
resources = filterResource(resources, filters...)
if app.Name == AddonObservabilityApplication {
resources = filterClusterObjectRefFromAddonObservability(resources)
}
// filter locations
if len(resources) == 0 {
return nil, fmt.Errorf("no supported resources detected in deployed resources")
}
if len(resources) == 1 {
return &resources[0], nil
}
opMap := ClusterObject2Map(resources)
var ops []string
for _, r := range opMap {
ops = append(ops, r)
}
prompt := &survey.Select{
Message: fmt.Sprintf("You have %d deployed resources in your app. Please choose one:", len(ops)),
Options: ops,
}
var selectedRsc string
err := survey.AskOne(prompt, &selectedRsc)
if err != nil {
return nil, fmt.Errorf("choosing resource err %w", err)
}
for k, resource := range ops {
if selectedRsc == resource {
return &resources[k], nil
}
}
return nil, fmt.Errorf("choosing resource err %w", err)
}
Refactor: align velaux env and CLI env, they both use K8s namespace as (#2975) * Refactor: use createOrUpdateNamespace as a common util function Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add ENV webservice handelr * Fix: fix Env usecase logic * Feat: Add Delete Env API Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: filter empty addon data Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: split makefiels and make it clear * Feat: add k8s utils test * Feat: Add env update interface Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: change env implementation Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: minor fix * Revert "Fix: minor fix" This reverts commit 9cafefa65a384795315924cb18e48681dd7086a1. * Fix: use appusecase as parameter Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Refactor: align CLI vela env with new env design Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: minor fix Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Feat: add page index and alias of env Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix tests and licence header * Fix: fix makefile and add default target Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update build swagger.json Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: change update env api Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: list env with alias * Feat: add log to env delete * Fix: can not get app status Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support update workflow and refactor code * Fix: lint * Fix: remove swagger check Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: fix cli vela delete * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: update test Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com> * Fix: app deploy unit test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: SortOrderDescending is not effective Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test case Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Feat: support default project/target/env * Fix: make test and add swagger * Fix: use separated datasource for unit test * Fix: app rollback bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: fix e2e test * Fix: kubeapi driver sort bug Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> * Fix: e2e test fix * Fix: try fix e2e test * Fix: api e2e test Signed-off-by: barnettZQG <barnett.zqg@gmail.com> Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2021-12-25 10:36:54 +08:00
// AskToChooseOneNamespace ask for choose one namespace as env
func AskToChooseOneNamespace(c client.Client, envMeta *types.EnvMeta) error {
var nsList v1.NamespaceList
if err := c.List(context.TODO(), &nsList); err != nil {
return err
}
var ops = []string{CreateCustomNamespace}
for _, r := range nsList.Items {
ops = append(ops, r.Name)
}
prompt := &survey.Select{
Message: "Would you like to choose an existing namespaces as your env?",
Options: ops,
}
err := survey.AskOne(prompt, &envMeta.Namespace)
if err != nil {
return fmt.Errorf("choosing namespace err %w", err)
}
if envMeta.Namespace == CreateCustomNamespace {
err = survey.AskOne(&survey.Input{
Message: "Please name the new namespace:",
}, &envMeta.Namespace)
if err != nil {
return err
}
return nil
}
for _, ns := range nsList.Items {
if ns.Name == envMeta.Namespace && envMeta.Name == "" {
envMeta.Name = ns.Labels[oam.LabelNamespaceOfEnvName]
return nil
}
}
return nil
}
func filterClusterObjectRefFromAddonObservability(resources []common.ClusterObjectReference) []common.ClusterObjectReference {
var observabilityResources []common.ClusterObjectReference
for _, res := range resources {
if res.Namespace == types.DefaultKubeVelaNS && res.Name == AddonObservabilityGrafanaSvc {
res.Kind = "Service"
res.APIVersion = "v1"
observabilityResources = append(observabilityResources, res)
}
}
resources = observabilityResources
return resources
}
// AskToChooseOneEnvResource will ask users to select one applied resource of the application if more than one
// resource is a map for component to applied resources
// return the selected ClusterObjectReference
func AskToChooseOneEnvResource(app *v1beta1.Application) (*common.ClusterObjectReference, error) {
return askToChooseOneResource(app, isWorkloadClusterObjectReferenceFilter)
}
// AskToChooseOnePortForwardEndpoint will ask user to select one applied resource as port forward endpoint
func AskToChooseOnePortForwardEndpoint(app *v1beta1.Application) (*common.ClusterObjectReference, error) {
return askToChooseOneResource(app, isPortForwardEndpointClusterObjectReferenceFilter)
}
func askToChooseOneInApplication(category string, options []string) (decision string, err error) {
if len(options) == 0 {
return "", fmt.Errorf("no %s exists in the application", category)
}
if len(options) == 1 {
return options[0], nil
}
prompt := &survey.Select{
Message: fmt.Sprintf("You have multiple %ss in your app. Please choose one %s: ", category, category),
Options: options,
}
if err = survey.AskOne(prompt, &decision); err != nil {
return "", errors2.Wrapf(err, "choosing %s failed", category)
}
return
}
// AskToChooseOneService will ask users to select one service of the application if more than one
func AskToChooseOneService(svcNames []string) (string, error) {
return askToChooseOneInApplication("service", svcNames)
}
2021-03-20 12:08:15 +08:00
// AskToChooseOnePods will ask users to select one pods of the resource if more than one
func AskToChooseOnePods(podNames []string) (string, error) {
return askToChooseOneInApplication("pod", podNames)
}
2021-03-20 12:08:15 +08:00
// ReadYamlToObject will read a yaml K8s object to runtime.Object
func ReadYamlToObject(path string, object k8sruntime.Object) error {
data, err := os.ReadFile(filepath.Clean(path))
2021-03-20 12:08:15 +08:00
if err != nil {
return err
}
return yaml.Unmarshal(data, object)
}
// ParseTerraformVariables get variables from Terraform Configuration
func ParseTerraformVariables(configuration string) (map[string]*tfconfig.Variable, error) {
p := hclparse.NewParser()
hclFile, diagnostic := p.ParseHCL([]byte(configuration), "")
if diagnostic != nil {
return nil, errors.New(diagnostic.Error())
}
mod := tfconfig.Module{Variables: map[string]*tfconfig.Variable{}}
diagnostic = tfconfig.LoadModuleFromFile(hclFile, &mod)
if diagnostic != nil {
return nil, errors.New(diagnostic.Error())
}
return mod.Variables, nil
}
// GenerateUnstructuredObj generate UnstructuredObj
func GenerateUnstructuredObj(name, ns string, gvk schema.GroupVersionKind) *unstructured.Unstructured {
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(gvk)
u.SetName(name)
u.SetNamespace(ns)
return u
}
// SetSpecObjIntoUnstructuredObj set UnstructuredObj spec field
func SetSpecObjIntoUnstructuredObj(spec interface{}, u *unstructured.Unstructured) error {
bts, err := json.Marshal(spec)
if err != nil {
return err
}
data := make(map[string]interface{})
if err := json.Unmarshal(bts, &data); err != nil {
return err
}
_ = unstructured.SetNestedMap(u.Object, data, "spec")
return nil
}
2021-08-11 23:05:10 +08:00
// NewK8sClient init a local k8s client which add oamcore scheme
func NewK8sClient() (client.Client, error) {
conf, err := config.GetConfig()
if err != nil {
return nil, err
}
scheme := k8sruntime.NewScheme()
if err := clientgoscheme.AddToScheme(scheme); err != nil {
return nil, err
}
if err := oamcore.AddToScheme(scheme); err != nil {
return nil, err
}
k8sClient, err := client.New(conf, client.Options{Scheme: scheme})
if err != nil {
return nil, err
}
return k8sClient, nil
}