From d262f526bd1d574925e13677bbeb16e0cd5a8c86 Mon Sep 17 00:00:00 2001 From: wuyan-dushang <1550693033@qq.com> Date: Mon, 2 Oct 2023 21:01:44 +0800 Subject: [PATCH] union fs --- app/dubboctl/cmd/root.go | 16 ++++- app/dubboctl/identifier/env.go | 39 +++++++---- app/dubboctl/internal/dubbo/deploy.tpl | 4 +- app/dubboctl/internal/dubbo/deployer.go | 2 + app/dubboctl/internal/dubbo/dubbo.go | 41 ++++++++++++ .../internal/filesystem/filesystem.go | 67 +++++++++++++++++++ app/dubboctl/internal/kube/component.go | 18 ++--- app/dubboctl/internal/manifest/common.go | 6 +- deploy/embedded.go | 21 ++++++ test/testclient/ddsc.go | 1 - 10 files changed, 186 insertions(+), 29 deletions(-) create mode 100644 deploy/embedded.go diff --git a/app/dubboctl/cmd/root.go b/app/dubboctl/cmd/root.go index 23fcce692..8744d5f49 100644 --- a/app/dubboctl/cmd/root.go +++ b/app/dubboctl/cmd/root.go @@ -34,15 +34,25 @@ type RootCommandConfig struct { // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute(args []string) { rootCmd := getRootCmd(args) + // when flag error occurs, print usage string. + // but if an error occurs when executing command, usage string will not be printed. + rootCmd.SetFlagErrorFunc(func(command *cobra.Command, err error) error { + command.Println(command.UsageString()) + + return err + }) + cobra.CheckErr(rootCmd.Execute()) } func getRootCmd(args []string) *cobra.Command { // rootCmd represents the base command when called without any subcommands rootCmd := &cobra.Command{ - Use: "dubboctl", - Short: "dubbo control interface", - Long: ``, + Use: "dubboctl", + Short: "dubbo control interface", + Long: ``, + SilenceErrors: true, + SilenceUsage: true, } cfg := RootCommandConfig{ diff --git a/app/dubboctl/identifier/env.go b/app/dubboctl/identifier/env.go index d5a9efe8c..362e13abe 100644 --- a/app/dubboctl/identifier/env.go +++ b/app/dubboctl/identifier/env.go @@ -16,19 +16,34 @@ package identifier import ( - "path/filepath" - "runtime" + "net/url" + + "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/filesystem" + "github.com/apache/dubbo-kubernetes/deploy" ) var ( - _, b, _, _ = runtime.Caller(0) - // Root folder of dubbo-admin - // This relies on the fact this file is 3 levels up from the root; if this changes, adjust the path below - Root = filepath.Join(filepath.Dir(b), "../../..") - Deploy = filepath.Join(Root, "/deploy") - Charts = filepath.Join(Deploy, "/charts") - Profiles = filepath.Join(Deploy, "profiles") - Addons = filepath.Join(Deploy, "addons") - AddonDashboards = filepath.Join(Addons, "dashboards") - AddonManifests = filepath.Join(Addons, "manifests") + // deploy dir is root in embed.FS + deployUri = &url.URL{ + Scheme: filesystem.EmbedSchema, + OmitHost: true, + } + + chartsUri = deployUri.JoinPath("charts") + profilesUri = deployUri.JoinPath("profiles") + addonsUri = deployUri.JoinPath("addons") + addonDashboardsUri = addonsUri.JoinPath("dashboards") + addonManifestsUri = addonsUri.JoinPath("manifests") + + Charts = chartsUri.String() + Profiles = profilesUri.String() + Addons = addonsUri.String() + AddonDashboards = addonDashboardsUri.String() + AddonManifests = addonManifestsUri.String() ) + +var UnionFS filesystem.UnionFS + +func init() { + UnionFS = filesystem.NewUnionFS(deploy.EmbedRootFS) +} diff --git a/app/dubboctl/internal/dubbo/deploy.tpl b/app/dubboctl/internal/dubbo/deploy.tpl index c4463fb66..9e643288d 100644 --- a/app/dubboctl/internal/dubbo/deploy.tpl +++ b/app/dubboctl/internal/dubbo/deploy.tpl @@ -29,7 +29,9 @@ spec: image: {{.Image}} env: - name: DUBBO_CTL_VERSION - value: 0.0.1 + value: 0.0.1{{if .Registry}} + - name: DUBBO_REGISTRY_ADDRESS + value: {{.Registry}}{{end}} ports: - containerPort: {{.Port}} name: dubbo diff --git a/app/dubboctl/internal/dubbo/deployer.go b/app/dubboctl/internal/dubbo/deployer.go index c78c534d5..94b52c2cb 100644 --- a/app/dubboctl/internal/dubbo/deployer.go +++ b/app/dubboctl/internal/dubbo/deployer.go @@ -56,6 +56,7 @@ type Deployment struct { TargetPort int NodePort int UseNodePort bool + Registry string UseProm bool } @@ -101,6 +102,7 @@ func (d *DeployApp) Deploy(ctx context.Context, f *Dubbo, option ...DeployOption TargetPort: targetPort, NodePort: f.Deploy.NodePort, UseNodePort: nodePort > 0, + Registry: f.Deploy.Registry, UseProm: f.Deploy.UseProm, }) if err != nil { diff --git a/app/dubboctl/internal/dubbo/dubbo.go b/app/dubboctl/internal/dubbo/dubbo.go index 5249ab4b7..40da180f7 100644 --- a/app/dubboctl/internal/dubbo/dubbo.go +++ b/app/dubboctl/internal/dubbo/dubbo.go @@ -128,6 +128,7 @@ type DeploySpec struct { ContainerPort int `yaml:"containerPort,omitempty"` TargetPort int `yaml:"targetPort,omitempty"` NodePort int `yaml:"nodePort,omitempty"` + Registry string `yaml:"registry,omitempty"` UseProm bool `yaml:"-"` } @@ -371,6 +372,46 @@ func (f *Dubbo) CheckLabels(ns string, client *Client) error { } if namespace != "" { + var name string + var dns string + + nacosSelector := client2.MatchingLabels{ + "dubbo.apache.org/nacos": "true", + } + + nacosList := &corev1.ServiceList{} + if err := client.KubeCtl.List(context.Background(), nacosList, nacosSelector, client2.InNamespace(namespace)); err != nil { + if errors2.IsNotFound(err) { + return nil + } else { + return err + } + } + if len(nacosList.Items) > 0 { + name = nacosList.Items[0].Name + dns = fmt.Sprintf("nacos://%s.%s.svc", name, namespace) + f.Deploy.Registry = dns + } + + zkSelector := client2.MatchingLabels{ + "dubbo.apache.org/zookeeper": "true", + } + + zkList := &corev1.ServiceList{} + if err := client.KubeCtl.List(context.Background(), zkList, zkSelector, client2.InNamespace(namespace)); err != nil { + if errors2.IsNotFound(err) { + return nil + } else { + return err + } + } + + if len(zkList.Items) > 0 { + name = zkList.Items[0].Name + dns = fmt.Sprintf("zookeeper://%s.%s.svc", name, namespace) + f.Deploy.Registry = dns + } + promSelector := client2.MatchingLabels{ "dubbo.apache.org/prometheus": "true", } diff --git a/app/dubboctl/internal/filesystem/filesystem.go b/app/dubboctl/internal/filesystem/filesystem.go index a19173d26..53c199146 100644 --- a/app/dubboctl/internal/filesystem/filesystem.go +++ b/app/dubboctl/internal/filesystem/filesystem.go @@ -19,9 +19,12 @@ package filesystem import ( "archive/zip" + "embed" + "errors" "fmt" "io" "io/fs" + "net/url" "os" "path" "path/filepath" @@ -267,6 +270,70 @@ func (m maskingFS) Readlink(link string) (string, error) { return m.fs.Readlink(link) } +const ( + EmbedSchema = "embed" +) + +// UnionFS is an os.FS and embed.FS union fs. +// Files in embed.FS has the header "embed://", and files in os.FS don't have this header. +type UnionFS struct { + embedFS embed.FS +} + +func NewUnionFS(embedFS embed.FS) UnionFS { + return UnionFS{ + embedFS: embedFS, + } +} + +func (u UnionFS) ReadFile(name string) ([]byte, error) { + uri, _ := url.Parse(name) + if uri != nil && uri.Scheme == EmbedSchema { + name = strings.TrimLeft(uri.Opaque, "/") + return u.embedFS.ReadFile(name) + } + + return os.ReadFile(name) +} + +func (u UnionFS) Open(name string) (fs.File, error) { + uri, _ := url.Parse(name) + if uri != nil && uri.Scheme == EmbedSchema { + name = strings.TrimLeft(uri.Opaque, "/") + return u.embedFS.Open(name) + } + + return os.Open(name) +} + +func (u UnionFS) ReadDir(name string) ([]fs.DirEntry, error) { + uri, _ := url.Parse(name) + if uri != nil && uri.Scheme == EmbedSchema { + name = strings.TrimLeft(uri.Opaque, "/") + return u.embedFS.ReadDir(name) + } + + return os.ReadDir(name) +} + +func (u UnionFS) Stat(name string) (fs.FileInfo, error) { + f, err := u.Open(name) + if err != nil { + return nil, err + } + + return f.Stat() +} + +func (u UnionFS) Readlink(link string) (string, error) { + uri, _ := url.Parse(link) + if uri != nil && uri.Scheme == EmbedSchema { + return "", errors.New("embed FS not support read link") + } + + return os.Readlink(link) +} + // CopyFromFS copies files from the `src` dir on the accessor Filesystem to local filesystem into `dest` dir. // The src path uses slashes as their separator. // The dest path uses OS specific separator. diff --git a/app/dubboctl/internal/kube/component.go b/app/dubboctl/internal/kube/component.go index eac53a5cf..17b0d21ee 100644 --- a/app/dubboctl/internal/kube/component.go +++ b/app/dubboctl/internal/kube/component.go @@ -16,7 +16,6 @@ package kube import ( - "os" "path" "strings" "unicode/utf8" @@ -26,6 +25,7 @@ import ( "github.com/apache/dubbo-kubernetes/app/dubboctl/identifier" "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/apis/dubbo.apache.org/v1alpha1" + "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/filesystem" "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/manifest" "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/manifest/render" "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/util" @@ -133,7 +133,7 @@ func NewAdminComponent(spec *v1alpha1.AdminSpec, opts ...ComponentOption) (Compo renderer, err := render.NewLocalRenderer( render.WithName(string(Admin)), render.WithNamespace(newOpts.Namespace), - render.WithFS(os.DirFS(newOpts.ChartPath)), + render.WithFS(filesystem.NewSubFS(newOpts.ChartPath, identifier.UnionFS)), render.WithDir("dubbo-admin")) if err != nil { return nil, err @@ -195,7 +195,7 @@ func NewGrafanaComponent(spec *v1alpha1.GrafanaSpec, opts ...ComponentOption) (C renderer, err = render.NewLocalRenderer( render.WithName(string(Grafana)), render.WithNamespace(newOpts.Namespace), - render.WithFS(os.DirFS(newOpts.ChartPath)), + render.WithFS(filesystem.NewSubFS(newOpts.ChartPath, identifier.UnionFS)), render.WithDir("grafana"), ) if err != nil { @@ -247,7 +247,7 @@ func NewNacosComponent(spec *v1alpha1.NacosSpec, opts ...ComponentOption) (Compo renderer, err := render.NewLocalRenderer( render.WithName(string(Nacos)), render.WithNamespace(newOpts.Namespace), - render.WithFS(os.DirFS(newOpts.ChartPath)), + render.WithFS(filesystem.NewSubFS(newOpts.ChartPath, identifier.UnionFS)), render.WithDir("nacos")) if err != nil { return nil, err @@ -309,7 +309,7 @@ func NewZookeeperComponent(spec *v1alpha1.ZookeeperSpec, opts ...ComponentOption renderer, err = render.NewLocalRenderer( render.WithName(string(Zookeeper)), render.WithNamespace(newOpts.Namespace), - render.WithFS(os.DirFS(newOpts.ChartPath)), + render.WithFS(filesystem.NewSubFS(newOpts.ChartPath, identifier.UnionFS)), render.WithDir("zookeeper"), ) if err != nil { @@ -374,7 +374,7 @@ func NewPrometheusComponent(spec *v1alpha1.PrometheusSpec, opts ...ComponentOpti renderer, err = render.NewLocalRenderer( render.WithName(string(Prometheus)), render.WithNamespace(newOpts.Namespace), - render.WithFS(os.DirFS(newOpts.ChartPath)), + render.WithFS(filesystem.NewSubFS(newOpts.ChartPath, identifier.UnionFS)), render.WithDir("prometheus"), ) if err != nil { @@ -439,7 +439,7 @@ func NewSkywalkingComponent(spec *v1alpha1.SkywalkingSpec, opts ...ComponentOpti renderer, err = render.NewLocalRenderer( render.WithName(string(Skywalking)), render.WithNamespace(newOpts.Namespace), - render.WithFS(os.DirFS(newOpts.ChartPath)), + render.WithFS(filesystem.NewSubFS(newOpts.ChartPath, identifier.UnionFS)), render.WithDir("skywalking"), ) if err != nil { @@ -504,7 +504,7 @@ func NewZipkinComponent(spec *v1alpha1.ZipkinSpec, opts ...ComponentOption) (Com renderer, err = render.NewLocalRenderer( render.WithName(string(Zipkin)), render.WithNamespace(newOpts.Namespace), - render.WithFS(os.DirFS(newOpts.ChartPath)), + render.WithFS(filesystem.NewSubFS(newOpts.ChartPath, identifier.UnionFS)), render.WithDir("zipkin"), ) if err != nil { @@ -583,7 +583,7 @@ func addDashboards(base string, namespace string) (string, error) { configMap.Data = make(map[string]string) dashboardName := "external-dashboard.json" dashboardPath := path.Join(identifier.AddonDashboards, dashboardName) - content, err := os.ReadFile(dashboardPath) + content, err := identifier.UnionFS.ReadFile(dashboardPath) if err != nil { return "", err } diff --git a/app/dubboctl/internal/manifest/common.go b/app/dubboctl/internal/manifest/common.go index da3a684ed..20c2b071d 100644 --- a/app/dubboctl/internal/manifest/common.go +++ b/app/dubboctl/internal/manifest/common.go @@ -17,10 +17,10 @@ package manifest import ( "fmt" - "os" "path" "strings" + "github.com/apache/dubbo-kubernetes/app/dubboctl/identifier" "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/apis/dubbo.apache.org/v1alpha1" "github.com/apache/dubbo-kubernetes/app/dubboctl/internal/util" @@ -68,7 +68,7 @@ func ReadYamlAndProfile(filenames []string, setFlags []string) (string, string, func ReadAndOverlayYamls(filenames []string) (string, error) { var output string for _, filename := range filenames { - file, err := os.ReadFile(strings.TrimSpace(filename)) + file, err := identifier.UnionFS.ReadFile(strings.TrimSpace(filename)) if err != nil { return "", err } @@ -108,7 +108,7 @@ func OverlaySetFlags(base string, setFlags []string) (string, error) { // It may add some filters in the future. func ReadProfilesNames(profilesPath string) ([]string, error) { var res []string - dir, err := os.ReadDir(profilesPath) + dir, err := identifier.UnionFS.ReadDir(profilesPath) if err != nil { return nil, err } diff --git a/deploy/embedded.go b/deploy/embedded.go new file mode 100644 index 000000000..190d93442 --- /dev/null +++ b/deploy/embedded.go @@ -0,0 +1,21 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package deploy + +import "embed" + +//go:embed all:addons all:charts all:profiles +var EmbedRootFS embed.FS diff --git a/test/testclient/ddsc.go b/test/testclient/ddsc.go index 289eee46d..5602efc6a 100644 --- a/test/testclient/ddsc.go +++ b/test/testclient/ddsc.go @@ -31,7 +31,6 @@ import ( api "github.com/apache/dubbo-kubernetes/api/resource/v1alpha1" "github.com/apache/dubbo-kubernetes/pkg/core/logger" "github.com/cenkalti/backoff" - "github.com/gogo/protobuf/proto" "google.golang.org/grpc" )