This is an automated email from the ASF dual-hosted git repository.
zhongxjian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-kubernetes.git
The following commit(s) were added to refs/heads/master by this push:
new 36c05f30 [operator] Supplementary code comments v2 (#646)
36c05f30 is described below
commit 36c05f300b231e8f46826141888b937c2cbfc59d
Author: Jian Zhong <[email protected]>
AuthorDate: Wed Mar 19 15:40:45 2025 +0800
[operator] Supplementary code comments v2 (#646)
---
operator/pkg/apis/types.go | 2 +-
operator/pkg/component/component.go | 60 ++++++++++++++++++++++---------------
operator/pkg/config/gvk.go | 49 ++++++------------------------
operator/pkg/config/marshal.go | 45 ----------------------------
operator/pkg/helm/helm.go | 14 ++++++---
operator/pkg/install/installer.go | 53 +++++++++++++++++++-------------
operator/pkg/install/waiter.go | 4 +++
operator/pkg/manifest/manifest.go | 57 ++++++++++++++++++-----------------
operator/pkg/manifest/name.go | 9 ++++--
operator/pkg/parts/parts.go | 1 +
operator/pkg/render/manifest.go | 30 +++++++++++++++++--
operator/pkg/render/postprocess.go | 8 ++++-
pkg/kube/client.go | 2 +-
13 files changed, 165 insertions(+), 169 deletions(-)
diff --git a/operator/pkg/apis/types.go b/operator/pkg/apis/types.go
index 73245c1f..e9810caa 100644
--- a/operator/pkg/apis/types.go
+++ b/operator/pkg/apis/types.go
@@ -88,7 +88,7 @@ type RegisterComponentSpec struct {
Raw map[string]any `json:"-"`
}
-type MetadataCompSpec struct {
+type DefaultCompSpec struct {
RegisterComponentSpec
}
diff --git a/operator/pkg/component/component.go
b/operator/pkg/component/component.go
index ca35a31a..9edc7891 100644
--- a/operator/pkg/component/component.go
+++ b/operator/pkg/component/component.go
@@ -25,6 +25,8 @@ import (
type Name string
+// DubboComponent names corresponding to the IstioOperator proto component
names.
+// These must be the same since they are used for struct traversal.
const (
BaseComponentName Name = "Base"
NacosRegisterComponentName Name = "Nacos"
@@ -33,15 +35,22 @@ const (
)
type Component struct {
- UserFacingName Name
- ContainerName string
- SpecName string
- ResourceType string
- ResourceName string
- Default bool
- HelmSubDir string
+ // UserFacingName is the component name in user-facing cases.
+ UserFacingName Name
+ // ContainerName maps a Name to the name of the container in a
Deployment.
+ ContainerName string
+ // SpecName is the yaml key in the DubboOperator spec.
+ SpecName string
+ // ResourceType maps a Name to the type of the rendered k8s resource.
+ ResourceType string
+ // ResourceName maps a Name to the name of the rendered k8s resource.
+ ResourceName string
+ // Default defines whether the component is enabled by default.
+ Default bool
+ // HelmSubDir is a mapping between a component name and the
subdirectory of the component Chart.
+ HelmSubDir string
+ // HelmValuesTreeRoot is the tree root in values YAML files for the
component.
HelmValuesTreeRoot string
- FlattenValues bool
}
var AllComponents = []Component{
@@ -100,29 +109,21 @@ var (
}
)
-func UserFacingCompName(name Name) string {
- s, ok := userFacingCompNames[name]
- if !ok {
- return "Unknown"
- }
- return s
-}
-
-func (c Component) Get(merged values.Map) ([]apis.MetadataCompSpec, error) {
+func (c Component) Get(merged values.Map) ([]apis.DefaultCompSpec, error) {
defaultNamespace := merged.GetPathString("metadata.namespace")
- var defaultResp []apis.MetadataCompSpec
+ var defaultResp []apis.DefaultCompSpec
def := c.Default
if def {
- defaultResp = []apis.MetadataCompSpec{{
+ defaultResp = []apis.DefaultCompSpec{{
RegisterComponentSpec: apis.RegisterComponentSpec{
Namespace: defaultNamespace,
}},
}
}
- buildSpec := func(m values.Map) (apis.MetadataCompSpec, error) {
- spec, err := values.ConvertMap[apis.MetadataCompSpec](m)
+ buildSpec := func(m values.Map) (apis.DefaultCompSpec, error) {
+ spec, err := values.ConvertMap[apis.DefaultCompSpec](m)
if err != nil {
- return apis.MetadataCompSpec{}, fmt.Errorf("fail to
convert %v: %v", c.SpecName, err)
+ return apis.DefaultCompSpec{}, fmt.Errorf("fail to
convert %v: %v", c.SpecName, err)
}
if spec.Namespace == "" {
@@ -134,6 +135,7 @@ func (c Component) Get(merged values.Map)
([]apis.MetadataCompSpec, error) {
spec.Raw = m
return spec, nil
}
+ // List of components
if c.ContainerName == "dashboard" {
s, ok := merged.GetPathMap("spec.dashboard." + c.SpecName)
if !ok {
@@ -147,7 +149,6 @@ func (c Component) Get(merged values.Map)
([]apis.MetadataCompSpec, error) {
return nil, nil
}
}
-
if c.ContainerName == "register-discovery" {
s, ok := merged.GetPathMap("spec.components.register." +
c.SpecName)
if !ok {
@@ -161,6 +162,7 @@ func (c Component) Get(merged values.Map)
([]apis.MetadataCompSpec, error) {
return nil, nil
}
}
+ // Single component
s, ok := merged.GetPathMap("spec.components." + c.SpecName)
if !ok {
return defaultResp, nil
@@ -172,5 +174,15 @@ func (c Component) Get(merged values.Map)
([]apis.MetadataCompSpec, error) {
if !(spec.Enabled.GetValueOrTrue()) {
return nil, nil
}
- return []apis.MetadataCompSpec{spec}, nil
+ return []apis.DefaultCompSpec{spec}, nil
+}
+
+// UserFacingCompName returns the name of the given component that should be
displayed to the user in high
+// level CLIs (like progress log).
+func UserFacingCompName(name Name) string {
+ s, ok := userFacingCompNames[name]
+ if !ok {
+ return "Unknown"
+ }
+ return s
}
diff --git a/operator/pkg/config/gvk.go b/operator/pkg/config/gvk.go
index 3f525be0..ee60360c 100644
--- a/operator/pkg/config/gvk.go
+++ b/operator/pkg/config/gvk.go
@@ -18,13 +18,7 @@
package config
import (
- "bytes"
- "encoding/json"
"fmt"
- gogojsonpb "github.com/gogo/protobuf/jsonpb"
- gogoproto "github.com/gogo/protobuf/proto"
- "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/reflect/protoreflect"
"k8s.io/apimachinery/pkg/runtime/schema"
)
@@ -40,10 +34,7 @@ func (g GroupVersionKind) String() string {
return g.CanonicalGroup() + "/" + g.Version + "/" + g.Kind
}
-func (g GroupVersionKind) CanonicalGroup() string {
- return CanoncalGroup(g.Group)
-}
-
+// Kubernetes returns the same GVK, using the Kubernetes object type.
func (g GroupVersionKind) Kubernetes() schema.GroupVersionKind {
return schema.GroupVersionKind{
Group: g.Group,
@@ -52,45 +43,23 @@ func (g GroupVersionKind) Kubernetes()
schema.GroupVersionKind {
}
}
-func CanoncalGroup(group string) string {
+// CanonicalGroup returns the group with defaulting applied. This means an
empty group will
+// be treated as "core", following Kubernetes API standards
+func CanonicalGroup(group string) string {
if group != "" {
return group
}
return "core"
}
-func FromK8sGVK(gvk schema.GroupVersionKind) GroupVersionKind {
+func (g GroupVersionKind) CanonicalGroup() string {
+ return CanonicalGroup(g.Group)
+}
+
+func FromKubernetesGVK(gvk schema.GroupVersionKind) GroupVersionKind {
return GroupVersionKind{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
}
}
-
-type Spec any
-
-func ToJSON(s Spec) ([]byte, error) {
- return toJSON(s, false)
-}
-
-func toJSON(s Spec, pretty bool) ([]byte, error) {
- indent := ""
- if pretty {
- indent = " "
- }
- if _, ok := s.(protoreflect.ProtoMessage); ok {
- if pb, ok := s.(proto.Message); ok {
- b, err := MarshalIndent(pb, indent)
- return b, err
- }
- }
- b := &bytes.Buffer{}
- if pb, ok := s.(gogoproto.Message); ok {
- err := (&gogojsonpb.Marshaler{Indent: indent}).Marshal(b, pb)
- return b.Bytes(), err
- }
- if pretty {
- return json.MarshalIndent(s, "", indent)
- }
- return json.Marshal(s)
-}
diff --git a/operator/pkg/config/marshal.go b/operator/pkg/config/marshal.go
deleted file mode 100644
index 3ff4bd6a..00000000
--- a/operator/pkg/config/marshal.go
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package config
-
-import (
- "errors"
- "github.com/golang/protobuf/jsonpb"
- legacyproto "github.com/golang/protobuf/proto"
- "google.golang.org/protobuf/proto"
-)
-
-func MarshalIndent(msg proto.Message, indent string) ([]byte, error) {
- res, err := ToJSONWithIndent(msg, indent)
- if err != nil {
- return nil, err
- }
- return []byte(res), err
-}
-
-func ToJSONWithIndent(msg proto.Message, indent string) (string, error) {
- return ToJSONWithOptions(msg, indent, false)
-}
-
-func ToJSONWithOptions(msg proto.Message, indent string, enumsAsInts bool)
(string, error) {
- if msg == nil {
- return "", errors.New("unexpected nil message")
- }
- m := jsonpb.Marshaler{Indent: indent, EnumsAsInts: enumsAsInts}
- return m.MarshalToString(legacyproto.MessageV1(msg))
-}
diff --git a/operator/pkg/helm/helm.go b/operator/pkg/helm/helm.go
index 86032c2c..49a9ce93 100644
--- a/operator/pkg/helm/helm.go
+++ b/operator/pkg/helm/helm.go
@@ -45,8 +45,11 @@ const (
type Warnings = util.Errors
-func Reader(namespace string, directory string, dop values.Map)
([]manifest.Manifest, util.Errors, error) {
- vals, ok := dop.GetPathMap("spec.values")
+// Render produces a set of fully rendered manifests from Helm.
+// Any warnings are also propagated up.
+// Note: this is the direct result of the Helm call. Postprocessing steps are
done later.
+func Render(namespace string, directory string, dop values.Map)
([]manifest.Manifest, util.Errors, error) {
+ val, ok := dop.GetPathMap("spec.values")
if !ok {
return nil, nil, fmt.Errorf("failed to get values from dop:
%v", ok)
}
@@ -54,7 +57,7 @@ func Reader(namespace string, directory string, dop
values.Map) ([]manifest.Mani
// pkgPath := dop.GetPathString("spec.packagePath")
f := manifests.BuiltinDir("")
chrt, err := loadChart(f, path)
- output, warnings, err := readerChart(namespace, vals, chrt)
+ output, warnings, err := renderChart(namespace, val, chrt)
if err != nil {
return nil, nil, fmt.Errorf("render chart: %v", err)
}
@@ -62,7 +65,8 @@ func Reader(namespace string, directory string, dop
values.Map) ([]manifest.Mani
return mfs, warnings, err
}
-func readerChart(namespace string, chrtVals values.Map, chrt *chart.Chart)
([]string, Warnings, error) {
+// renderChart renders the given chart with the given values and returns the
resulting YAML manifest string.
+func renderChart(namespace string, chrtVals values.Map, chrt *chart.Chart)
([]string, Warnings, error) {
opts := chartutil.ReleaseOptions{
Name: "dubbo",
Namespace: namespace,
@@ -102,6 +106,7 @@ func readerChart(namespace string, chrtVals values.Map,
chrt *chart.Chart) ([]st
return res, warnings, nil
}
+// loadChart reads a chart from the filesystem. This is like loader.LoadDir
but allows a fs.FS.
func loadChart(f fs.FS, root string) (*chart.Chart, error) {
fnames, err := getFilesRecursive(f, root)
if err != nil {
@@ -126,6 +131,7 @@ func loadChart(f fs.FS, root string) (*chart.Chart, error) {
return loader.LoadFiles(bfs)
}
+// stripPrefix removes the given prefix from prefix.
func stripPrefix(path, prefix string) string {
pl := len(strings.Split(prefix, "/"))
pv := strings.Split(path, "/")
diff --git a/operator/pkg/install/installer.go
b/operator/pkg/install/installer.go
index 0c278f25..4a4348a3 100644
--- a/operator/pkg/install/installer.go
+++ b/operator/pkg/install/installer.go
@@ -50,6 +50,29 @@ type Installer struct {
Logger clog.Logger
}
+// InstallManifests applies a set of rendered manifests to the cluster.
+func (i Installer) InstallManifests(manifests []manifest.ManifestSet) error {
+ err := i.installSystemNamespace()
+ if err != nil {
+ return err
+ }
+ if err := i.install(manifests); err != nil {
+ return err
+ }
+ return nil
+}
+
+// installSystemNamespace creates the system namespace before installation.
+func (i Installer) installSystemNamespace() error {
+ ns := i.Values.GetPathStringOr("metadata.namespace", "dubbo-system")
+ if err := util.CreateNamespace(i.Kube.Kube(), ns, i.DryRun); err != nil
{
+ return err
+ }
+ return nil
+}
+
+// install takes rendered manifests and actually applies them to the cluster.
+// This considers ordering based on components.
func (i Installer) install(manifests []manifest.ManifestSet) error {
var mu sync.Mutex
var wg sync.WaitGroup
@@ -103,25 +126,7 @@ func (i Installer) install(manifests
[]manifest.ManifestSet) error {
return nil
}
-func (i Installer) InstallManifests(manifests []manifest.ManifestSet) error {
- err := i.installSystemNamespace()
- if err != nil {
- return err
- }
- if err := i.install(manifests); err != nil {
- return err
- }
- return nil
-}
-
-func (i Installer) installSystemNamespace() error {
- ns := i.Values.GetPathStringOr("metadata.namespace", "dubbo-system")
- if err := util.CreateNamespace(i.Kube.Kube(), ns, i.DryRun); err != nil
{
- return err
- }
- return nil
-}
-
+// applyManifestSet applies a set of manifests to the cluster.
func (i Installer) applyManifestSet(manifestSet manifest.ManifestSet) error {
componentNames := string(manifestSet.Components)
manifests := manifestSet.Manifests
@@ -146,8 +151,8 @@ func (i Installer) applyManifestSet(manifestSet
manifest.ManifestSet) error {
return nil
}
+// serverSideApply creates or updates an object in the API server depending on
whether it already exists.
func (i Installer) serverSideApply(obj manifest.Manifest) error {
- var dryRun []string
const fieldManager = "dubbo-operator"
dc, err := i.Kube.DynamicClientFor(obj.GroupVersionKind(),
obj.Unstructured, "")
if err != nil {
@@ -155,6 +160,7 @@ func (i Installer) serverSideApply(obj manifest.Manifest)
error {
}
objStr := fmt.Sprintf("%s/%s/%s", obj.GetKind(), obj.GetNamespace(),
obj.GetName())
+ var dryRun []string
if i.DryRun {
return nil
}
@@ -174,9 +180,11 @@ func (i Installer) applyLabelsAndAnnotations(obj
manifest.Manifest, cname string
return manifest.Manifest{}, err
}
}
+ // We're mutating the unstructured, must rebuild the YAML.
return manifest.FromObject(obj.Unstructured)
}
+// prune removes resources that are in the cluster, but not a part of the
currently installed set of objects.
func (i Installer) prune(manifests []manifest.ManifestSet) error {
if i.DryRun {
return nil
@@ -184,11 +192,12 @@ func (i Installer) prune(manifests
[]manifest.ManifestSet) error {
i.ProgressInfo.SetState(progress.StatePruning)
+ // Build up a map of component->resources, so we know what to keep
around
excluded := map[component.Name]sets.String{}
+ // Include all components in case we disabled some.
for _, c := range component.AllComponents {
excluded[c.UserFacingName] = sets.New[string]()
}
-
for _, mfs := range manifests {
for _, m := range mfs.Manifests {
excluded[mfs.Components].Insert(m.Hash())
@@ -225,6 +234,8 @@ func (i Installer) prune(manifests []manifest.ManifestSet)
error {
if
obj.GetLabels()[manifest.OwningResourceNotPruned] == "true" {
continue
}
+ // Label mismatch. Provided objects don't
select against the component, so this likely means the object
+ // is for another component.
if
!compLabels.Matches(klabels.Set(obj.GetLabels())) {
continue
}
diff --git a/operator/pkg/install/waiter.go b/operator/pkg/install/waiter.go
index fe838f58..c506111d 100644
--- a/operator/pkg/install/waiter.go
+++ b/operator/pkg/install/waiter.go
@@ -35,11 +35,14 @@ import (
"time"
)
+// deployment holds associated replicaSets for a deployment
type deployment struct {
replicaSets *appsv1.ReplicaSet
deployment *appsv1.Deployment
}
+// WaitForResources polls to get the current status of various objects that
are not immediately ready
+// until all are ready or a timeout is reached.
func WaitForResources(objects []manifest.Manifest, client kube.CLIClient,
waitTimeout time.Duration, dryRun bool, l *progress.ManifestInfo) error {
if dryRun {
return nil
@@ -48,6 +51,7 @@ func WaitForResources(objects []manifest.Manifest, client
kube.CLIClient, waitTi
var notReady []string
var debugInfo map[string]string
+ // Check if we are ready immediately, to avoid the 2s delay below when
we are already ready
if ready, _, _, err := waitForResources(objects, client, l); err == nil
&& ready {
return nil
}
diff --git a/operator/pkg/manifest/manifest.go
b/operator/pkg/manifest/manifest.go
index eee442ad..4f650358 100644
--- a/operator/pkg/manifest/manifest.go
+++ b/operator/pkg/manifest/manifest.go
@@ -35,29 +35,6 @@ type ManifestSet struct {
Manifests []Manifest
}
-func FromJSON(j []byte) (Manifest, error) {
- us := &unstructured.Unstructured{}
- if err := json.Unmarshal(j, us); err != nil {
- return Manifest{}, err
- }
- y, err := yaml.Marshal(us)
- if err != nil {
- return Manifest{}, err
- }
- return Manifest{Unstructured: us, Content: string(y)}, nil
-}
-
-func FromYAML(y []byte) (Manifest, error) {
- us := &unstructured.Unstructured{}
- if err := yaml.Unmarshal(y, us); err != nil {
- return Manifest{}, err
- }
- return Manifest{
- Unstructured: us,
- Content: string(y),
- }, nil
-}
-
func FromObject(us *unstructured.Unstructured) (Manifest, error) {
c, err := yaml.Marshal(us)
if err != nil {
@@ -69,6 +46,12 @@ func FromObject(us *unstructured.Unstructured) (Manifest,
error) {
}, nil
}
+// ParseMultiple splits a string containing potentially many YAML objects, and
parses them.
+func ParseMultiple(output string) ([]Manifest, error) {
+ return Parse(parts.SplitString(output))
+}
+
+// Parse parses a list of YAML objects.
func Parse(output []string) ([]Manifest, error) {
result := make([]Manifest, 0, len(output))
for _, m := range output {
@@ -77,6 +60,7 @@ func Parse(output []string) ([]Manifest, error) {
return nil, err
}
if mf.GetObjectKind().GroupVersionKind().Kind == "" {
+ // This is not an object. Could be empty template,
comments only, etc
continue
}
result = append(result, mf)
@@ -84,8 +68,8 @@ func Parse(output []string) ([]Manifest, error) {
return result, nil
}
-func ParseMultiple(output string) ([]Manifest, error) {
- return Parse(parts.SplitString(output))
+func (m Manifest) Hash() string {
+ return ObjectHash(m.Unstructured)
}
func ObjectHash(o *unstructured.Unstructured) string {
@@ -97,6 +81,25 @@ func ObjectHash(o *unstructured.Unstructured) string {
return k + ":" + o.GetNamespace() + ":" + o.GetName()
}
-func (m Manifest) Hash() string {
- return ObjectHash(m.Unstructured)
+func FromJSON(j []byte) (Manifest, error) {
+ us := &unstructured.Unstructured{}
+ if err := json.Unmarshal(j, us); err != nil {
+ return Manifest{}, err
+ }
+ y, err := yaml.Marshal(us)
+ if err != nil {
+ return Manifest{}, err
+ }
+ return Manifest{Unstructured: us, Content: string(y)}, nil
+}
+
+func FromYAML(y []byte) (Manifest, error) {
+ us := &unstructured.Unstructured{}
+ if err := yaml.Unmarshal(y, us); err != nil {
+ return Manifest{}, err
+ }
+ return Manifest{
+ Unstructured: us,
+ Content: string(y),
+ }, nil
}
diff --git a/operator/pkg/manifest/name.go b/operator/pkg/manifest/name.go
index fdc0b763..f0ed4174 100644
--- a/operator/pkg/manifest/name.go
+++ b/operator/pkg/manifest/name.go
@@ -18,8 +18,13 @@
package manifest
const (
- OwningResourceName = "install.operator.dubbo.io/owning-resource"
+ // OwningResourceName represents the name of the owner to which the
resource relates.
+ OwningResourceName = "install.operator.dubbo.io/owning-resource"
+ // OwningResourceNamespace represents the namespace of the owner to
which the resource relates.
OwningResourceNamespace =
"install.operator.dubbo.io/owning-resource-namespace"
- DubboComponentLabel = "operator.dubbo.io/component"
+ // DubboComponentLabel indicates which Dubbo component a resource
belongs to.
+ DubboComponentLabel = "operator.dubbo.io/component"
+ // OwningResourceNotPruned indicates that the resource should not be
pruned during reconciliation cycles,
+ // note this will not prevent the resource from being deleted if the
owning resource is deleted.
OwningResourceNotPruned =
"install.operator.dubbo.io/owning-resource-not-pruned"
)
diff --git a/operator/pkg/parts/parts.go b/operator/pkg/parts/parts.go
index bf86c35b..204a93d6 100644
--- a/operator/pkg/parts/parts.go
+++ b/operator/pkg/parts/parts.go
@@ -22,6 +22,7 @@ import (
"strings"
)
+// SplitString splits the given yaml doc if it's multipart document.
func SplitString(yamlText string) []string {
out := make([]string, 0)
scanner := bufio.NewScanner(strings.NewReader(yamlText))
diff --git a/operator/pkg/render/manifest.go b/operator/pkg/render/manifest.go
index 1fce1892..26b5d8dc 100644
--- a/operator/pkg/render/manifest.go
+++ b/operator/pkg/render/manifest.go
@@ -34,7 +34,14 @@ import (
"strings"
)
+// MergeInputs merges the various configuration inputs into one single
DubboOperator.
func MergeInputs(filenames []string, flags []string) (values.Map, error) {
+ // We want our precedence order to be:
+ // base < profile < auto-detected settings < files (in order) < --set
flags (in order).
+ // The tricky part is that we don't know where to read the profile from
until we read the files/--set flags.
+ // To handle this, we will first build up these values,
+ // then apply them on top of the base once we determine which base to
use.
+ // Initial base values.
ConfigBase, err := values.MapFromJSON([]byte(`{
"apiVersion": "install.dubbo.io/v1alpha1",
"kind": "DubboOperator",
@@ -45,6 +52,7 @@ func MergeInputs(filenames []string, flags []string)
(values.Map, error) {
return nil, err
}
+ // Apply all passed in files
for i, fn := range filenames {
var b []byte
var err error
@@ -65,22 +73,25 @@ func MergeInputs(filenames []string, flags []string)
(values.Map, error) {
if err != nil {
return nil, fmt.Errorf("yaml Unmarshal err:%v", err)
}
+ // Special hack to allow an empty spec to work. Should this be
more generic?
if m["spec"] == nil {
delete(m, "spec")
}
ConfigBase.MergeFrom(m)
}
-
+ // Apply any --set flags
if err := ConfigBase.SetSpecPaths(flags...); err != nil {
return nil, err
}
path := ConfigBase.GetPathString("")
profile := ConfigBase.GetPathString("spec.profile")
+ // Now we have the base
base, err := readProfile(path, profile)
if err != nil {
return base, err
}
+ // Merge the user values on top
base.MergeFrom(ConfigBase)
return base, nil
}
@@ -96,6 +107,7 @@ func checkDops(s string) error {
return nil
}
+// readProfile reads a profile, from given path.
func readProfile(path, profile string) (values.Map, error) {
if profile == "" {
profile = "default"
@@ -128,11 +140,18 @@ func readBuiltinProfile(path, profile string)
(values.Map, error) {
return values.MapFromYAML(pb)
}
+// GenerateManifest produces fully rendered Kubernetes objects from rendering
Helm charts.
+// Inputs can be files and --set strings.
+// Client is option; if it is provided, cluster-specific settings can be
auto-detected.
+// Logger is also option; if it is provided warning messages may be logged.
func GenerateManifest(files []string, setFlags []string, logger clog.Logger, _
kube.Client) ([]manifest.ManifestSet, values.Map, error) {
+ // First, compute our final configuration input. This will be in the
form of an DubboOperator, but as an unstructured values.Map.
+ // This allows safe access to get/fetch values dynamically, and avoids
issues are typing and whether we should emit empty fields.
merged, err := MergeInputs(files, setFlags)
if err != nil {
return nil, nil, fmt.Errorf("merge inputs: %v %v", err)
}
+ // Validate the config. This can emit warnings to the logger. If force
is set, errors will be logged as warnings but not returned.
if err := validateDubboOperator(merged, logger); err != nil {
return nil, nil, fmt.Errorf("validateDubboOperator err:%v", err)
}
@@ -144,12 +163,15 @@ func GenerateManifest(files []string, setFlags []string,
logger clog.Logger, _ k
return nil, nil, fmt.Errorf("get component %v: %v",
comp.UserFacingName, err)
}
for _, spec := range specs {
+ // Each component may get a different view of the
values; modify them as needed (with a copy)
compVals := applyComponentValuesToHelmValues(comp,
spec, merged)
- rendered, warnings, err := helm.Reader(spec.Namespace,
comp.HelmSubDir, compVals)
+ // Render the chart.
+ rendered, warnings, err := helm.Render(spec.Namespace,
comp.HelmSubDir, compVals)
if err != nil {
return nil, nil, fmt.Errorf("helm render: %v",
err)
}
chartWarnings = util.AppendErrs(chartWarnings, warnings)
+ // DubboOperator has a variety of processing steps that
are done *after* Helm, such as patching. Apply any of these steps.
finalized, err := postProcess(comp, rendered, compVals)
if err != nil {
return nil, nil, fmt.Errorf("post process: %v",
err)
@@ -167,6 +189,7 @@ func GenerateManifest(files []string, setFlags []string,
logger clog.Logger, _ k
}
}
+ // Log any warnings we got from the charts
if logger != nil {
for _, w := range chartWarnings {
logger.LogAndErrorf("%s %v", "❗", w)
@@ -193,7 +216,8 @@ func validateDubboOperator(dop values.Map, logger
clog.Logger) error {
return nil
}
-func applyComponentValuesToHelmValues(comp component.Component, spec
apis.MetadataCompSpec, merged values.Map) values.Map {
+// applyComponentValuesToHelmValues translates a generic values set into a
component-specific one.
+func applyComponentValuesToHelmValues(_ component.Component, spec
apis.DefaultCompSpec, merged values.Map) values.Map {
if spec.Namespace != "" {
spec.Namespace = "dubbo-system"
}
diff --git a/operator/pkg/render/postprocess.go
b/operator/pkg/render/postprocess.go
index 004a3f20..ae211a17 100644
--- a/operator/pkg/render/postprocess.go
+++ b/operator/pkg/render/postprocess.go
@@ -32,10 +32,14 @@ type patchContext struct {
PostProcess func([]byte) ([]byte, error)
}
+// postProcess applies any manifest manipulation to be done after Helm chart
rendering.
func postProcess(_ component.Component, manifests []manifest.Manifest, _
values.Map) ([]manifest.Manifest, error) {
+ // needPatching builds a map of manifest index -> patch. This ensures
we only do the full round-tripping once per object.
needPatching := map[int][]patchContext{}
+ // For anything needing a patch, apply them.
for idx, patches := range needPatching {
m := manifests[idx]
+ // Convert to JSON, which the StrategicMergePatch requires
baseJSON, err := yaml.YAMLToJSON([]byte(m.Content))
if err != nil {
return nil, err
@@ -44,7 +48,7 @@ func postProcess(_ component.Component, manifests
[]manifest.Manifest, _ values.
if err != nil {
return nil, err
}
-
+ // Apply all the patches.
for _, patch := range patches {
newBytes, err :=
strategicpatch.StrategicMergePatch(baseJSON, []byte(patch.Patch), typed)
if err != nil {
@@ -58,10 +62,12 @@ func postProcess(_ component.Component, manifests
[]manifest.Manifest, _ values.
}
baseJSON = newBytes
}
+ // Rebuild our manifest.
nm, err := manifest.FromJSON(baseJSON)
if err != nil {
return nil, err
}
+ // Update the manifests list.
manifests[idx] = nm
}
diff --git a/pkg/kube/client.go b/pkg/kube/client.go
index ad6073db..e0526802 100644
--- a/pkg/kube/client.go
+++ b/pkg/kube/client.go
@@ -174,7 +174,7 @@ func (c *client) DynamicClientFor(gvk
schema.GroupVersionKind, obj *unstructured
}
func (c *client) bestEffortToGVR(gvk schema.GroupVersionKind, obj
*unstructured.Unstructured, namespace string) (schema.GroupVersionResource,
bool) {
- if s, f :=
collections.All.FindByGroupVersionAliasesKind(config.FromK8sGVK(gvk)); f {
+ if s, f :=
collections.All.FindByGroupVersionAliasesKind(config.FromKubernetesGVK(gvk)); f
{
gvr := s.GroupVersionResource()
gvr.Version = gvk.Version
return gvr, !s.IsClusterScoped()