| 
									
										
										
										
											2021-03-26 15:24:19 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 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. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-16 18:55:01 +08:00
										 |  |  | package common | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2020-11-18 16:08:16 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-01-28 18:36:52 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2020-11-18 16:08:16 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2021-01-28 18:36:52 +08:00
										 |  |  | 	"os/exec" | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	"cuelang.org/go/cue" | 
					
						
							| 
									
										
										
										
											2021-08-11 13:59:46 +08:00
										 |  |  | 	"cuelang.org/go/cue/ast" | 
					
						
							| 
									
										
										
										
											2022-01-25 15:03:38 +08:00
										 |  |  | 	"cuelang.org/go/cue/build" | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | 	"cuelang.org/go/cue/format" | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	"cuelang.org/go/encoding/openapi" | 
					
						
							| 
									
										
										
										
											2021-02-20 04:11:26 +08:00
										 |  |  | 	"github.com/AlecAivazis/survey/v2" | 
					
						
							| 
									
										
										
										
											2022-07-01 23:31:15 +08:00
										 |  |  | 	cloudshellv1alpha1 "github.com/cloudtty/cloudtty/pkg/apis/cloudshell/v1alpha1" | 
					
						
							| 
									
										
										
										
											2021-06-03 11:23:20 +08:00
										 |  |  | 	"github.com/hashicorp/hcl/v2/hclparse" | 
					
						
							|  |  |  | 	"github.com/oam-dev/terraform-config-inspect/tfconfig" | 
					
						
							| 
									
										
										
										
											2021-03-24 08:01:24 +08:00
										 |  |  | 	kruise "github.com/openkruise/kruise-api/apps/v1alpha1" | 
					
						
							| 
									
										
										
										
											2022-06-24 18:03:04 +08:00
										 |  |  | 	kruisev1alpha1 "github.com/openkruise/rollouts/api/v1alpha1" | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 	errors2 "github.com/pkg/errors" | 
					
						
							| 
									
										
										
										
											2020-10-15 11:51:41 +08:00
										 |  |  | 	certmanager "github.com/wonderflow/cert-manager-api/pkg/apis/certmanager/v1" | 
					
						
							| 
									
										
										
										
											2022-06-24 19:34:51 +08:00
										 |  |  | 	yamlv3 "gopkg.in/yaml.v3" | 
					
						
							| 
									
										
										
										
											2021-03-24 08:01:24 +08:00
										 |  |  | 	istioclientv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1" | 
					
						
							| 
									
										
										
										
											2021-12-25 10:36:54 +08:00
										 |  |  | 	v1 "k8s.io/api/core/v1" | 
					
						
							| 
									
										
										
										
											2021-03-24 08:01:24 +08:00
										 |  |  | 	crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | 
					
						
							| 
									
										
										
										
											2021-07-30 10:02:51 +08:00
										 |  |  | 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | 
					
						
							| 
									
										
										
										
											2020-11-17 14:25:58 +08:00
										 |  |  | 	k8sruntime "k8s.io/apimachinery/pkg/runtime" | 
					
						
							| 
									
										
										
										
											2021-07-30 10:02:51 +08:00
										 |  |  | 	"k8s.io/apimachinery/pkg/runtime/schema" | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 	clientgoscheme "k8s.io/client-go/kubernetes/scheme" | 
					
						
							| 
									
										
										
										
											2021-09-14 20:35:10 +08:00
										 |  |  | 	apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" | 
					
						
							| 
									
										
										
										
											2022-05-12 10:47:35 +08:00
										 |  |  | 	metricsV1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1" | 
					
						
							| 
									
										
										
										
											2021-11-02 17:20:00 +08:00
										 |  |  | 	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" | 
					
						
							| 
									
										
										
										
											2020-11-17 14:25:58 +08:00
										 |  |  | 	"sigs.k8s.io/controller-runtime/pkg/client/config" | 
					
						
							| 
									
										
										
										
											2021-08-15 10:53:05 +08:00
										 |  |  | 	"sigs.k8s.io/yaml" | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-12 10:47:35 +08:00
										 |  |  | 	prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1" | 
					
						
							|  |  |  | 	clustergatewayapi "github.com/oam-dev/cluster-gateway/pkg/apis/cluster/v1alpha1" | 
					
						
							| 
									
										
										
										
											2022-05-13 14:24:14 +08:00
										 |  |  | 	terraformapiv1 "github.com/oam-dev/terraform-controller/api/v1beta1" | 
					
						
							| 
									
										
										
										
											2022-05-12 10:47:35 +08:00
										 |  |  | 	terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2" | 
					
						
							| 
									
										
										
										
											2022-03-08 14:20:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 08:01:24 +08:00
										 |  |  | 	oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev" | 
					
						
							| 
									
										
										
										
											2021-11-02 14:45:15 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/apis/core.oam.dev/common" | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" | 
					
						
							| 
									
										
										
										
											2021-03-24 08:01:24 +08:00
										 |  |  | 	oamstandard "github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1" | 
					
						
							| 
									
										
										
										
											2021-12-22 21:08:00 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/apis/types" | 
					
						
							| 
									
										
										
										
											2021-06-02 15:37:06 +08:00
										 |  |  | 	velacue "github.com/oam-dev/kubevela/pkg/cue" | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/cue/model" | 
					
						
							| 
									
										
										
										
											2022-01-25 15:03:38 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/cue/packages" | 
					
						
							| 
									
										
										
										
											2021-12-25 10:36:54 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/oam" | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2020-11-17 17:46:56 +08:00
										 |  |  | 	// Scheme defines the default KubeVela schema
 | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 	Scheme = k8sruntime.NewScheme() | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-22 21:08:00 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	// AddonObservabilityApplication is the application name for Addon Observability
 | 
					
						
							|  |  |  | 	AddonObservabilityApplication = "addon-observability" | 
					
						
							|  |  |  | 	// AddonObservabilityGrafanaSvc is grafana service name for Addon Observability
 | 
					
						
							|  |  |  | 	AddonObservabilityGrafanaSvc = "grafana" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-25 10:36:54 +08:00
										 |  |  | // CreateCustomNamespace display the create namespace message
 | 
					
						
							|  |  |  | const CreateCustomNamespace = "create new namespace" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | func init() { | 
					
						
							|  |  |  | 	_ = clientgoscheme.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2021-09-14 20:35:10 +08:00
										 |  |  | 	_ = apiregistrationv1.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2021-03-24 08:01:24 +08:00
										 |  |  | 	_ = crdv1.AddToScheme(Scheme) | 
					
						
							|  |  |  | 	_ = oamcore.AddToScheme(Scheme) | 
					
						
							|  |  |  | 	_ = oamstandard.AddToScheme(Scheme) | 
					
						
							|  |  |  | 	_ = istioclientv1beta1.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 	_ = certmanager.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2021-03-24 08:01:24 +08:00
										 |  |  | 	_ = kruise.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2022-05-09 15:10:31 +08:00
										 |  |  | 	_ = terraformapi.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2022-05-13 14:24:14 +08:00
										 |  |  | 	_ = terraformapiv1.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2021-08-06 10:46:31 +08:00
										 |  |  | 	_ = ocmclusterv1alpha1.Install(Scheme) | 
					
						
							| 
									
										
										
										
											2021-11-02 17:20:00 +08:00
										 |  |  | 	_ = ocmclusterv1.Install(Scheme) | 
					
						
							| 
									
										
										
										
											2021-08-06 10:46:31 +08:00
										 |  |  | 	_ = ocmworkv1.Install(Scheme) | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | 	_ = clustergatewayapi.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2022-03-08 14:20:36 +08:00
										 |  |  | 	_ = metricsV1beta1api.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2022-06-24 18:03:04 +08:00
										 |  |  | 	_ = kruisev1alpha1.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2022-05-12 10:47:35 +08:00
										 |  |  | 	_ = prismclusterv1alpha1.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2022-07-01 23:31:15 +08:00
										 |  |  | 	_ = cloudshellv1alpha1.AddToScheme(Scheme) | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 	// +kubebuilder:scaffold:scheme
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-12 14:33:44 +08:00
										 |  |  | // HTTPOption define the https options
 | 
					
						
							|  |  |  | type HTTPOption struct { | 
					
						
							|  |  |  | 	Username string | 
					
						
							|  |  |  | 	Password string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 17:46:56 +08:00
										 |  |  | // InitBaseRestConfig will return reset config for create controller runtime client
 | 
					
						
							| 
									
										
										
										
											2021-03-23 16:30:49 +08:00
										 |  |  | func InitBaseRestConfig() (Args, error) { | 
					
						
							| 
									
										
										
										
											2022-01-07 15:49:27 +08:00
										 |  |  | 	args := Args{ | 
					
						
							|  |  |  | 		Schema: Scheme, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, err := args.GetConfig() | 
					
						
							| 
									
										
										
										
											2021-08-06 17:10:52 +08:00
										 |  |  | 	if err != nil && os.Getenv("IGNORE_KUBE_CONFIG") != "true" { | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 		fmt.Println("get kubeConfig err", err) | 
					
						
							|  |  |  | 		os.Exit(1) | 
					
						
							| 
									
										
										
										
											2021-10-29 15:07:15 +08:00
										 |  |  | 	} else if err != nil { | 
					
						
							|  |  |  | 		return Args{}, err | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-07 15:49:27 +08:00
										 |  |  | 	return args, nil | 
					
						
							| 
									
										
										
										
											2020-09-24 16:30:12 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-11-18 16:08:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-08 13:10:47 +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") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 19:34:51 +08:00
										 |  |  | // HTTPGetResponse use HTTP option and default client to send request and get raw response
 | 
					
						
							|  |  |  | func HTTPGetResponse(ctx context.Context, url string, opts *HTTPOption) (*http.Response, error) { | 
					
						
							| 
									
										
										
										
											2020-11-18 16:08:16 +08:00
										 |  |  | 	// Change NewRequest to NewRequestWithContext and pass context it
 | 
					
						
							|  |  |  | 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-04-12 14:33:44 +08:00
										 |  |  | 	if opts != nil && len(opts.Username) != 0 && len(opts.Password) != 0 { | 
					
						
							|  |  |  | 		req.SetBasicAuth(opts.Username, opts.Password) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-06-24 19:34:51 +08:00
										 |  |  | 	return http.DefaultClient.Do(req) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // HTTPGetWithOption use HTTP option and default client to send get request
 | 
					
						
							|  |  |  | func HTTPGetWithOption(ctx context.Context, url string, opts *HTTPOption) ([]byte, error) { | 
					
						
							|  |  |  | 	resp, err := HTTPGetResponse(ctx, url, opts) | 
					
						
							| 
									
										
										
										
											2020-11-18 16:08:16 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	//nolint:errcheck
 | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							| 
									
										
										
										
											2021-09-06 18:33:42 +08:00
										 |  |  | 	return io.ReadAll(resp.Body) | 
					
						
							| 
									
										
										
										
											2020-11-18 16:08:16 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-24 19:34:51 +08:00
										 |  |  | // HTTPGetKubernetesObjects use HTTP requests to load resources from remote url
 | 
					
						
							|  |  |  | func HTTPGetKubernetesObjects(ctx context.Context, url string) ([]*unstructured.Unstructured, error) { | 
					
						
							|  |  |  | 	resp, err := HTTPGetResponse(ctx, url, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	//nolint:errcheck
 | 
					
						
							|  |  |  | 	defer resp.Body.Close() | 
					
						
							|  |  |  | 	decoder := yamlv3.NewDecoder(resp.Body) | 
					
						
							|  |  |  | 	var uns []*unstructured.Unstructured | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		obj := &unstructured.Unstructured{Object: map[string]interface{}{}} | 
					
						
							|  |  |  | 		if err := decoder.Decode(obj.Object); err != nil { | 
					
						
							|  |  |  | 			if errors.Is(err, io.EOF) { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("failed to decode object: %w", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		uns = append(uns, obj) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return uns, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | // GetCUEParameterValue converts definitions to cue format
 | 
					
						
							| 
									
										
										
										
											2022-01-25 15:03:38 +08:00
										 |  |  | func GetCUEParameterValue(cueStr string, pd *packages.PackageDiscover) (cue.Value, error) { | 
					
						
							|  |  |  | 	var template *cue.Instance | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 	if pd != nil { | 
					
						
							|  |  |  | 		bi := build.NewContext().NewInstance("", nil) | 
					
						
							|  |  |  | 		err := bi.AddFile("-", cueStr+velacue.BaseTemplate) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return cue.Value{}, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		template, err = pd.ImportPackagesAndBuildInstance(bi) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return cue.Value{}, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		r := cue.Runtime{} | 
					
						
							|  |  |  | 		template, err = r.Compile("", cueStr+velacue.BaseTemplate) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return cue.Value{}, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	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) | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 		if paraDef.Name == model.ParameterFieldName { | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 			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 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | 	paramOnlyIns, err := RefineParameterInstance(inst) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	defaultConfig := &openapi.Config{} | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | 	b, err := openapi.Gen(paramOnlyIns, defaultConfig) | 
					
						
							| 
									
										
										
										
											2020-12-18 10:18:16 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var out = &bytes.Buffer{} | 
					
						
							|  |  |  | 	_ = json.Indent(out, b, "", "   ") | 
					
						
							|  |  |  | 	return out.Bytes(), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 13:59:46 +08:00
										 |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 				if label, ok := field.Label.(*ast.Ident); ok && label.Name == "#"+model.ParameterFieldName { | 
					
						
							| 
									
										
										
										
											2021-08-11 13:59:46 +08:00
										 |  |  | 					return decl.(*ast.Field).Value | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 	paramVal := inst.LookupDef(model.ParameterFieldName) | 
					
						
							| 
									
										
										
										
											2021-08-11 13:59:46 +08:00
										 |  |  | 	return paramVal.Syntax(opts...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | // RefineParameterInstance refines cue instance to merely include `parameter` identifier
 | 
					
						
							|  |  |  | func RefineParameterInstance(inst *cue.Instance) (*cue.Instance, error) { | 
					
						
							|  |  |  | 	r := cue.Runtime{} | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 	paramVal := inst.LookupDef(model.ParameterFieldName) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | 	var paramOnlyStr string | 
					
						
							|  |  |  | 	switch k := paramVal.IncompleteKind(); k { | 
					
						
							|  |  |  | 	case cue.StructKind, cue.ListKind: | 
					
						
							| 
									
										
										
										
											2021-08-11 13:59:46 +08:00
										 |  |  | 		paramSyntax, _ := format.Node(extractParameterDefinitionNodeFromInstance(inst)) | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 		paramOnlyStr = fmt.Sprintf("#%s: %s\n", model.ParameterFieldName, string(paramSyntax)) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | 	case cue.IntKind, cue.StringKind, cue.FloatKind, cue.BoolKind: | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 		paramOnlyStr = fmt.Sprintf("#%s: %v", model.ParameterFieldName, paramVal) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | 	case cue.BottomKind: | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 		paramOnlyStr = fmt.Sprintf("#%s: {}", model.ParameterFieldName) | 
					
						
							| 
									
										
										
										
											2021-06-15 13:36:23 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-28 18:36:52 +08:00
										 |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-02-20 04:11:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-02 14:45:15 +08:00
										 |  |  | // ClusterObject2Map convert ClusterObjectReference to a readable map
 | 
					
						
							|  |  |  | func ClusterObject2Map(refs []common.ClusterObjectReference) map[string]string { | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | 	clusterResourceRefTmpl := "Cluster: %s | Namespace: %s | Kind: %s | Name: %s" | 
					
						
							| 
									
										
										
										
											2021-11-02 14:45:15 +08:00
										 |  |  | 	objs := make(map[string]string, len(refs)) | 
					
						
							|  |  |  | 	for _, r := range refs { | 
					
						
							|  |  |  | 		if r.Cluster == "" { | 
					
						
							|  |  |  | 			r.Cluster = "local" | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | 		objs[r.Cluster+"/"+r.Namespace+"/"+r.Name+"/"+r.Kind] = fmt.Sprintf(clusterResourceRefTmpl, r.Cluster, r.Namespace, r.Kind, r.Name) | 
					
						
							| 
									
										
										
										
											2021-11-02 14:45:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return objs | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | // ResourceLocation indicates the resource location
 | 
					
						
							|  |  |  | type ResourceLocation struct { | 
					
						
							|  |  |  | 	Cluster   string | 
					
						
							|  |  |  | 	Namespace string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 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") | 
					
						
							| 
									
										
										
										
											2021-12-22 21:08:00 +08:00
										 |  |  | var isPortForwardEndpointClusterObjectReferenceFilter = clusterObjectReferenceTypeFilterGenerator("Deployment", | 
					
						
							|  |  |  | 	"StatefulSet", "CloneSet", "Job", "Service", "HelmRelease") | 
					
						
							| 
									
										
										
										
											2022-04-08 17:22:05 +08:00
										 |  |  | var resourceNameClusterObjectReferenceFilter = func(resourceName []string) clusterObjectReferenceFilter { | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | 	return func(reference common.ClusterObjectReference) bool { | 
					
						
							| 
									
										
										
										
											2022-04-08 17:22:05 +08:00
										 |  |  | 		if len(resourceName) == 0 { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for _, r := range resourceName { | 
					
						
							|  |  |  | 			if r == reference.Name { | 
					
						
							|  |  |  | 				return true | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 	return | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | func askToChooseOneResource(app *v1beta1.Application, filters ...clusterObjectReferenceFilter) (*common.ClusterObjectReference, error) { | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | 	resources := app.Status.AppliedResources | 
					
						
							|  |  |  | 	if len(resources) == 0 { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("no resources in the application deployed yet") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 	resources = filterResource(resources, filters...) | 
					
						
							| 
									
										
										
										
											2021-12-22 21:08:00 +08:00
										 |  |  | 	if app.Name == AddonObservabilityApplication { | 
					
						
							|  |  |  | 		resources = filterClusterObjectRefFromAddonObservability(resources) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | 	// filter locations
 | 
					
						
							| 
									
										
										
										
											2021-11-02 14:45:15 +08:00
										 |  |  | 	if len(resources) == 0 { | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 		return nil, fmt.Errorf("no supported resources detected in deployed resources") | 
					
						
							| 
									
										
										
										
											2021-11-02 14:45:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	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{ | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | 		Message: fmt.Sprintf("You have %d deployed resources in your app. Please choose one:", len(ops)), | 
					
						
							| 
									
										
										
										
											2021-11-02 14:45:15 +08:00
										 |  |  | 		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) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-22 21:08:00 +08:00
										 |  |  | 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-08 17:22:05 +08:00
										 |  |  | func removeEmptyString(items []string) []string { | 
					
						
							|  |  |  | 	r := []string{} | 
					
						
							|  |  |  | 	for _, i := range items { | 
					
						
							|  |  |  | 		if i != "" { | 
					
						
							|  |  |  | 			r = append(r, i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return r | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | // 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
 | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | func AskToChooseOneEnvResource(app *v1beta1.Application, resourceName ...string) (*common.ClusterObjectReference, error) { | 
					
						
							|  |  |  | 	filters := []clusterObjectReferenceFilter{isWorkloadClusterObjectReferenceFilter} | 
					
						
							| 
									
										
										
										
											2022-04-08 17:22:05 +08:00
										 |  |  | 	_resourceName := removeEmptyString(resourceName) | 
					
						
							|  |  |  | 	filters = append(filters, resourceNameClusterObjectReferenceFilter(_resourceName)) | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | 	return askToChooseOneResource(app, filters...) | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AskToChooseOnePortForwardEndpoint will ask user to select one applied resource as port forward endpoint
 | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | func AskToChooseOnePortForwardEndpoint(app *v1beta1.Application, resourceName ...string) (*common.ClusterObjectReference, error) { | 
					
						
							|  |  |  | 	filters := []clusterObjectReferenceFilter{isPortForwardEndpointClusterObjectReferenceFilter} | 
					
						
							| 
									
										
										
										
											2022-04-08 17:22:05 +08:00
										 |  |  | 	_resourceName := removeEmptyString(resourceName) | 
					
						
							|  |  |  | 	filters = append(filters, resourceNameClusterObjectReferenceFilter(_resourceName)) | 
					
						
							| 
									
										
										
										
											2022-03-30 17:56:59 +08:00
										 |  |  | 	return askToChooseOneResource(app, filters...) | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func askToChooseOneInApplication(category string, options []string) (decision string, err error) { | 
					
						
							|  |  |  | 	if len(options) == 0 { | 
					
						
							|  |  |  | 		return "", fmt.Errorf("no %s exists in the application", category) | 
					
						
							| 
									
										
										
										
											2021-02-20 04:11:26 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 	if len(options) == 1 { | 
					
						
							|  |  |  | 		return options[0], nil | 
					
						
							| 
									
										
										
										
											2021-02-20 04:11:26 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	prompt := &survey.Select{ | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 		Message: fmt.Sprintf("You have multiple %ss in your app. Please choose one %s: ", category, category), | 
					
						
							|  |  |  | 		Options: options, | 
					
						
							| 
									
										
										
										
											2021-02-20 04:11:26 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 	if err = survey.AskOne(prompt, &decision); err != nil { | 
					
						
							|  |  |  | 		return "", errors2.Wrapf(err, "choosing %s failed", category) | 
					
						
							| 
									
										
										
										
											2021-02-20 04:11:26 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 	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-02-20 04:11:26 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-03-20 12:08:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | // AskToChooseOnePods will ask users to select one pods of the resource if more than one
 | 
					
						
							|  |  |  | func AskToChooseOnePods(podNames []string) (string, error) { | 
					
						
							| 
									
										
										
										
											2021-11-09 19:08:47 +08:00
										 |  |  | 	return askToChooseOneInApplication("pod", podNames) | 
					
						
							| 
									
										
										
										
											2021-11-07 08:54:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2021-09-06 18:33:42 +08:00
										 |  |  | 	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) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-03 11:23:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ParseTerraformVariables get variables from Terraform Configuration
 | 
					
						
							| 
									
										
										
										
											2022-01-05 19:45:30 +08:00
										 |  |  | func ParseTerraformVariables(configuration string) (map[string]*tfconfig.Variable, map[string]*tfconfig.Output, error) { | 
					
						
							| 
									
										
										
										
											2021-06-03 11:23:20 +08:00
										 |  |  | 	p := hclparse.NewParser() | 
					
						
							|  |  |  | 	hclFile, diagnostic := p.ParseHCL([]byte(configuration), "") | 
					
						
							|  |  |  | 	if diagnostic != nil { | 
					
						
							| 
									
										
										
										
											2022-01-05 19:45:30 +08:00
										 |  |  | 		return nil, nil, errors.New(diagnostic.Error()) | 
					
						
							| 
									
										
										
										
											2021-06-03 11:23:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-05 19:45:30 +08:00
										 |  |  | 	mod := tfconfig.Module{Variables: map[string]*tfconfig.Variable{}, Outputs: map[string]*tfconfig.Output{}} | 
					
						
							| 
									
										
										
										
											2021-06-03 11:23:20 +08:00
										 |  |  | 	diagnostic = tfconfig.LoadModuleFromFile(hclFile, &mod) | 
					
						
							|  |  |  | 	if diagnostic != nil { | 
					
						
							| 
									
										
										
										
											2022-01-05 19:45:30 +08:00
										 |  |  | 		return nil, nil, errors.New(diagnostic.Error()) | 
					
						
							| 
									
										
										
										
											2021-06-03 11:23:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-05 19:45:30 +08:00
										 |  |  | 	return mod.Variables, mod.Outputs, nil | 
					
						
							| 
									
										
										
										
											2021-06-03 11:23:20 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-30 10:02:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-06-24 19:34:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // FilterObjectsByCondition filter object slices by condition function
 | 
					
						
							|  |  |  | func FilterObjectsByCondition(objs []*unstructured.Unstructured, filter func(unstructured2 *unstructured.Unstructured) bool) (outs []*unstructured.Unstructured) { | 
					
						
							|  |  |  | 	for _, obj := range objs { | 
					
						
							|  |  |  | 		if filter(obj) { | 
					
						
							|  |  |  | 			outs = append(outs, obj) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } |