github.com/oam-dev/kubevela@v1.9.11/pkg/workflow/providers/oam/apply.go (about) 1 /* 2 Copyright 2021 The KubeVela Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package oam 18 19 import ( 20 "context" 21 "encoding/json" 22 "strings" 23 24 "cuelang.org/go/cue/cuecontext" 25 "github.com/pkg/errors" 26 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 27 "sigs.k8s.io/controller-runtime/pkg/client" 28 29 monitorContext "github.com/kubevela/pkg/monitor/context" 30 wfContext "github.com/kubevela/workflow/pkg/context" 31 "github.com/kubevela/workflow/pkg/cue/model/sets" 32 "github.com/kubevela/workflow/pkg/cue/model/value" 33 wfTypes "github.com/kubevela/workflow/pkg/types" 34 35 "github.com/oam-dev/kubevela/apis/core.oam.dev/common" 36 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 37 "github.com/oam-dev/kubevela/pkg/appfile" 38 "github.com/oam-dev/kubevela/pkg/oam" 39 ) 40 41 const ( 42 // ProviderName is provider name for install. 43 ProviderName = "oam" 44 ) 45 46 // ComponentApply apply oam component. 47 type ComponentApply func(ctx context.Context, comp common.ApplicationComponent, patcher *value.Value, clusterName string, overrideNamespace string) (*unstructured.Unstructured, []*unstructured.Unstructured, bool, error) 48 49 // ComponentRender render oam component. 50 type ComponentRender func(ctx context.Context, comp common.ApplicationComponent, patcher *value.Value, clusterName string, overrideNamespace string) (*unstructured.Unstructured, []*unstructured.Unstructured, error) 51 52 // ComponentHealthCheck health check oam component. 53 type ComponentHealthCheck func(ctx context.Context, comp common.ApplicationComponent, patcher *value.Value, clusterName string, overrideNamespace string) (bool, *unstructured.Unstructured, []*unstructured.Unstructured, error) 54 55 // WorkloadRenderer renderer to render application component into workload 56 type WorkloadRenderer func(ctx context.Context, comp common.ApplicationComponent) (*appfile.Component, error) 57 58 type provider struct { 59 render ComponentRender 60 apply ComponentApply 61 app *v1beta1.Application 62 af *appfile.Appfile 63 cli client.Client 64 } 65 66 // RenderComponent render component 67 func (p *provider) RenderComponent(ctx monitorContext.Context, _ wfContext.Context, v *value.Value, _ wfTypes.Action) error { 68 comp, patcher, clusterName, overrideNamespace, err := lookUpCompInfo(v) 69 if err != nil { 70 return err 71 } 72 workload, traits, err := p.render(ctx, *comp, patcher, clusterName, overrideNamespace) 73 if err != nil { 74 return err 75 } 76 77 if workload != nil { 78 if err := v.FillObject(workload.Object, "output"); err != nil { 79 return errors.WithMessage(err, "FillOutput") 80 } 81 } 82 83 for _, trait := range traits { 84 name := trait.GetLabels()[oam.TraitResource] 85 if name != "" { 86 if err := v.FillObject(trait.Object, "outputs", name); err != nil { 87 return errors.WithMessage(err, "FillOutputs") 88 } 89 } 90 } 91 92 return nil 93 } 94 95 // ApplyComponent apply component. 96 func (p *provider) ApplyComponent(ctx monitorContext.Context, _ wfContext.Context, v *value.Value, act wfTypes.Action) error { 97 comp, patcher, clusterName, overrideNamespace, err := lookUpCompInfo(v) 98 if err != nil { 99 return err 100 } 101 workload, traits, healthy, err := p.apply(ctx, *comp, patcher, clusterName, overrideNamespace) 102 if err != nil { 103 return err 104 } 105 106 if workload != nil { 107 if err := v.FillObject(workload.Object, "output"); err != nil { 108 return errors.WithMessage(err, "FillOutput") 109 } 110 } 111 112 for _, trait := range traits { 113 name := trait.GetLabels()[oam.TraitResource] 114 if name != "" { 115 if err := v.FillObject(trait.Object, "outputs", name); err != nil { 116 return errors.WithMessage(err, "FillOutputs") 117 } 118 } 119 } 120 121 waitHealthy, err := v.GetBool("waitHealthy") 122 if err != nil { 123 waitHealthy = true 124 } 125 126 if waitHealthy && !healthy { 127 act.Wait("wait healthy") 128 } 129 return nil 130 } 131 132 func lookUpCompInfo(v *value.Value) (*common.ApplicationComponent, *value.Value, string, string, error) { 133 compSettings, err := v.LookupValue("value") 134 if err != nil { 135 return nil, nil, "", "", err 136 } 137 comp := &common.ApplicationComponent{} 138 139 if err := compSettings.UnmarshalTo(comp); err != nil { 140 return nil, nil, "", "", err 141 } 142 patcher, err := v.LookupValue("patch") 143 if err != nil { 144 patcher = nil 145 } 146 clusterName, err := v.GetString("cluster") 147 if err != nil { 148 clusterName = "" 149 } 150 overrideNamespace, err := v.GetString("namespace") 151 if err != nil { 152 overrideNamespace = "" 153 } 154 return comp, patcher, clusterName, overrideNamespace, nil 155 } 156 157 // LoadComponent load component describe info in application. 158 func (p *provider) LoadComponent(ctx monitorContext.Context, _ wfContext.Context, v *value.Value, _ wfTypes.Action) error { 159 app := &v1beta1.Application{} 160 // if specify `app`, use specified application otherwise use default application from provider 161 appSettings, err := v.LookupValue("app") 162 if err != nil { 163 if strings.Contains(err.Error(), "not exist") { 164 app = p.app 165 } else { 166 return err 167 } 168 } else { 169 if err := appSettings.UnmarshalTo(app); err != nil { 170 return err 171 } 172 } 173 for _, _comp := range app.Spec.Components { 174 comp, err := p.af.LoadDynamicComponent(ctx, p.cli, _comp.DeepCopy()) 175 if err != nil { 176 return err 177 } 178 comp.Inputs = nil 179 comp.Outputs = nil 180 jt, err := json.Marshal(comp) 181 if err != nil { 182 return err 183 } 184 vs := string(jt) 185 cuectx := cuecontext.New() 186 val := cuectx.CompileString(vs) 187 if s, err := sets.OpenBaiscLit(val); err == nil { 188 v := cuectx.BuildFile(s) 189 str, err := sets.ToString(v) 190 if err != nil { 191 return err 192 } 193 vs = str 194 } 195 if err := v.FillRaw(vs, "value", comp.Name); err != nil { 196 return err 197 } 198 } 199 return nil 200 } 201 202 // LoadComponentInOrder load component describe info in application output will be a list with order defined in application. 203 func (p *provider) LoadComponentInOrder(ctx monitorContext.Context, _ wfContext.Context, v *value.Value, _ wfTypes.Action) error { 204 app := &v1beta1.Application{} 205 // if specify `app`, use specified application otherwise use default application from provider 206 appSettings, err := v.LookupValue("app") 207 if err != nil { 208 if strings.Contains(err.Error(), "not exist") { 209 app = p.app 210 } else { 211 return err 212 } 213 } else { 214 if err := appSettings.UnmarshalTo(app); err != nil { 215 return err 216 } 217 } 218 comps := make([]common.ApplicationComponent, len(app.Spec.Components)) 219 for idx, _comp := range app.Spec.Components { 220 comp, err := p.af.LoadDynamicComponent(ctx, p.cli, _comp.DeepCopy()) 221 if err != nil { 222 return err 223 } 224 comp.Inputs = nil 225 comp.Outputs = nil 226 comps[idx] = *comp 227 } 228 if err := v.FillObject(comps, "value"); err != nil { 229 return err 230 } 231 return nil 232 } 233 234 // LoadPolicies load policy describe info in application. 235 func (p *provider) LoadPolicies(_ monitorContext.Context, _ wfContext.Context, v *value.Value, _ wfTypes.Action) error { 236 for _, po := range p.app.Spec.Policies { 237 if err := v.FillObject(po, "value", po.Name); err != nil { 238 return err 239 } 240 } 241 return nil 242 } 243 244 // Install register handlers to provider discover. 245 func Install(p wfTypes.Providers, app *v1beta1.Application, af *appfile.Appfile, cli client.Client, apply ComponentApply, render ComponentRender) { 246 prd := &provider{ 247 render: render, 248 apply: apply, 249 app: app.DeepCopy(), 250 af: af, 251 cli: cli, 252 } 253 p.Register(ProviderName, map[string]wfTypes.Handler{ 254 "component-render": prd.RenderComponent, 255 "component-apply": prd.ApplyComponent, 256 "load": prd.LoadComponent, 257 "load-policies": prd.LoadPolicies, 258 "load-comps-in-order": prd.LoadComponentInOrder, 259 }) 260 }