github.com/kubevela/workflow@v0.6.0/pkg/tasks/template/load.go (about) 1 /* 2 Copyright 2022 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 template 18 19 import ( 20 "context" 21 "embed" 22 "fmt" 23 24 "github.com/pkg/errors" 25 apierrors "k8s.io/apimachinery/pkg/api/errors" 26 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/apimachinery/pkg/types" 29 "sigs.k8s.io/controller-runtime/pkg/client" 30 ) 31 32 var ( 33 //go:embed static 34 templateFS embed.FS 35 ) 36 37 const ( 38 templateDir = "static" 39 ) 40 41 type namespaceContextKey int 42 43 const ( 44 // DefinitionNamespace is context key to define workflow run namespace 45 DefinitionNamespace namespaceContextKey = iota 46 // SystemDefinitionNamespace is the system definition namespace 47 systemDefinitionNamespace string = "vela-system" 48 ) 49 50 // Loader load task definition template. 51 type Loader interface { 52 LoadTemplate(ctx context.Context, name string) (string, error) 53 } 54 55 // WorkflowStepLoader load workflowStep task definition template. 56 type WorkflowStepLoader struct { 57 loadDefinition func(ctx context.Context, capName string) (string, error) 58 } 59 60 // LoadTemplate gets the workflow step definition. 61 func (loader *WorkflowStepLoader) LoadTemplate(ctx context.Context, name string) (string, error) { 62 files, err := templateFS.ReadDir(templateDir) 63 if err != nil { 64 return "", err 65 } 66 67 staticFilename := name + ".cue" 68 for _, file := range files { 69 if staticFilename == file.Name() { 70 fileName := fmt.Sprintf("%s/%s", templateDir, file.Name()) 71 content, err := templateFS.ReadFile(fileName) 72 return string(content), err 73 } 74 } 75 76 return loader.loadDefinition(ctx, name) 77 } 78 79 // NewWorkflowStepTemplateLoader create a task template loader. 80 func NewWorkflowStepTemplateLoader(client client.Client) Loader { 81 return &WorkflowStepLoader{ 82 loadDefinition: func(ctx context.Context, capName string) (string, error) { 83 return getDefinitionTemplate(ctx, client, capName) 84 }, 85 } 86 } 87 88 type def struct { 89 Spec struct { 90 Schematic struct { 91 CUE struct { 92 Template string `json:"template"` 93 } `json:"cue"` 94 } `json:"schematic"` 95 } `json:"spec,omitempty"` 96 } 97 98 func getDefinitionTemplate(ctx context.Context, cli client.Client, definitionName string) (string, error) { 99 const ( 100 definitionAPIVersion = "core.oam.dev/v1beta1" 101 kindWorkflowStepDefinition = "WorkflowStepDefinition" 102 ) 103 definition := &unstructured.Unstructured{} 104 definition.SetAPIVersion(definitionAPIVersion) 105 definition.SetKind(kindWorkflowStepDefinition) 106 ns := getDefinitionNamespaceWithCtx(ctx) 107 if err := cli.Get(ctx, types.NamespacedName{Name: definitionName, Namespace: ns}, definition); err != nil { 108 if apierrors.IsNotFound(err) { 109 if err := cli.Get(ctx, types.NamespacedName{Name: definitionName, Namespace: systemDefinitionNamespace}, definition); err != nil { 110 return "", err 111 } 112 } else { 113 return "", err 114 } 115 } 116 d := new(def) 117 if err := runtime.DefaultUnstructuredConverter.FromUnstructured(definition.Object, d); err != nil { 118 return "", errors.Wrap(err, "invalid workflow step definition") 119 } 120 return d.Spec.Schematic.CUE.Template, nil 121 } 122 123 func getDefinitionNamespaceWithCtx(ctx context.Context) string { 124 var ns string 125 if run := ctx.Value(DefinitionNamespace); run == nil { 126 ns = systemDefinitionNamespace 127 } else { 128 ns = run.(string) 129 } 130 return ns 131 }