1// Copyright 2020 Istio Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package helmreconciler 16 17import ( 18 "io" 19 "strings" 20 21 jsonpatch "github.com/evanphx/json-patch" 22 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 23 "k8s.io/apimachinery/pkg/runtime" 24 25 "istio.io/istio/operator/pkg/name" 26 "istio.io/pkg/log" 27) 28 29const ( 30 // MetadataNamespace is the namespace for mesh metadata (labels, annotations) 31 MetadataNamespace = "install.operator.istio.io" 32 // OwningResourceName represents the name of the owner to which the resource relates 33 OwningResourceName = MetadataNamespace + "/owning-resource" 34 // OwningResourceNamespace represents the namespace of the owner to which the resource relates 35 OwningResourceNamespace = MetadataNamespace + "/owning-resource-namespace" 36 // operatorLabelStr indicates Istio operator is managing this resource. 37 operatorLabelStr = name.OperatorAPINamespace + "/managed" 38 // operatorReconcileStr indicates that the operator will reconcile the resource. 39 operatorReconcileStr = "Reconcile" 40 // IstioComponentLabelStr indicates which Istio component a resource belongs to. 41 IstioComponentLabelStr = name.OperatorAPINamespace + "/component" 42 // istioVersionLabelStr indicates the Istio version of the installation. 43 istioVersionLabelStr = name.OperatorAPINamespace + "/version" 44) 45 46var ( 47 scope = log.RegisterScope("installer", "installer", 0) 48) 49 50func init() { 51 // Tree representation and wait channels are an inversion of ComponentDependencies and are constructed from it. 52 buildInstallTree() 53 for _, parent := range ComponentDependencies { 54 for _, child := range parent { 55 DependencyWaitCh[child] = make(chan struct{}, 1) 56 } 57 } 58} 59 60// ComponentTree represents a tree of component dependencies. 61type ComponentTree map[name.ComponentName]interface{} 62type componentNameToListMap map[name.ComponentName][]name.ComponentName 63 64var ( 65 // ComponentDependencies is a tree of component dependencies. The semantics are ComponentDependencies[cname] gives 66 // the subtree of components that must wait for cname to be installed before starting installation themselves. 67 ComponentDependencies = componentNameToListMap{ 68 name.PilotComponentName: { 69 name.PolicyComponentName, 70 name.TelemetryComponentName, 71 name.CNIComponentName, 72 name.IngressComponentName, 73 name.EgressComponentName, 74 name.AddonComponentName, 75 }, 76 name.IstioBaseComponentName: { 77 name.PilotComponentName, 78 }, 79 } 80 81 // InstallTree is a top down hierarchy tree of dependencies where children must wait for the parent to complete 82 // before starting installation. 83 InstallTree = make(ComponentTree) 84 // DependencyWaitCh is a map of signaling channels. A parent with children ch1...chN will signal 85 // DependencyWaitCh[ch1]...DependencyWaitCh[chN] when it's completely installed. 86 DependencyWaitCh = make(map[name.ComponentName]chan struct{}) 87) 88 89// buildInstallTree builds a tree from buildInstallTree where parents are the root of each subtree. 90func buildInstallTree() { 91 // Starting with root, recursively insert each first level child into each node. 92 insertChildrenRecursive(name.IstioBaseComponentName, InstallTree, ComponentDependencies) 93} 94 95func insertChildrenRecursive(componentName name.ComponentName, tree ComponentTree, children componentNameToListMap) { 96 tree[componentName] = make(ComponentTree) 97 for _, child := range children[componentName] { 98 insertChildrenRecursive(child, tree[componentName].(ComponentTree), children) 99 } 100} 101 102// InstallTreeString returns a string representation of the dependency tree. 103func InstallTreeString() string { 104 var sb strings.Builder 105 buildInstallTreeString(name.IstioBaseComponentName, "", &sb) 106 return sb.String() 107} 108 109func buildInstallTreeString(componentName name.ComponentName, prefix string, sb io.StringWriter) { 110 _, _ = sb.WriteString(prefix + string(componentName) + "\n") 111 if _, ok := InstallTree[componentName].(ComponentTree); !ok { 112 return 113 } 114 for k := range InstallTree[componentName].(ComponentTree) { 115 buildInstallTreeString(k, prefix+" ", sb) 116 } 117} 118 119// applyOverlay applies an overlay using JSON patch strategy over the current Object in place. 120func applyOverlay(current, overlay runtime.Object) error { 121 cj, err := runtime.Encode(unstructured.UnstructuredJSONScheme, current) 122 if err != nil { 123 return err 124 } 125 uj, err := runtime.Encode(unstructured.UnstructuredJSONScheme, overlay) 126 if err != nil { 127 return err 128 } 129 merged, err := jsonpatch.MergePatch(cj, uj) 130 if err != nil { 131 return err 132 } 133 return runtime.DecodeInto(unstructured.UnstructuredJSONScheme, merged, current) 134} 135