|  | 
|  | 1 | +// Copyright 2020 The SQLFlow Authors. All rights reserved. | 
|  | 2 | +// Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 3 | +// you may not use this file except in compliance with the License. | 
|  | 4 | +// You may obtain a copy of the License at | 
|  | 5 | +// | 
|  | 6 | +// http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 7 | +// | 
|  | 8 | +// Unless required by applicable law or agreed to in writing, software | 
|  | 9 | +// distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 10 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 11 | +// See the License for the specific language governing permissions and | 
|  | 12 | +// limitations under the License. | 
|  | 13 | + | 
|  | 14 | +package experimental | 
|  | 15 | + | 
|  | 16 | +import ( | 
|  | 17 | +"bytes" | 
|  | 18 | +"fmt" | 
|  | 19 | +"os" | 
|  | 20 | +"strconv" | 
|  | 21 | +"text/template" | 
|  | 22 | + | 
|  | 23 | +pb "sqlflow.org/sqlflow/go/proto" | 
|  | 24 | +"sqlflow.org/sqlflow/go/workflow/couler" | 
|  | 25 | +) | 
|  | 26 | + | 
|  | 27 | +var workflowTTL = 24 * 3600 | 
|  | 28 | + | 
|  | 29 | +type stepContext struct { | 
|  | 30 | +Code string | 
|  | 31 | +StepIndex int | 
|  | 32 | +Image string | 
|  | 33 | +} | 
|  | 34 | + | 
|  | 35 | +type coulerFiller struct { | 
|  | 36 | +StepList []*stepContext | 
|  | 37 | +DataSource string | 
|  | 38 | +StepEnvs map[string]string | 
|  | 39 | +WorkflowTTL int | 
|  | 40 | +SecretName string | 
|  | 41 | +SecretData string | 
|  | 42 | +Resources string | 
|  | 43 | +} | 
|  | 44 | + | 
|  | 45 | +// CodeGenCouler generate couler code to generate a workflow | 
|  | 46 | +func CodeGenCouler(stepList []*stepContext, session *pb.Session) (string, error) { | 
|  | 47 | +var workflowResourcesEnv = "SQLFLOW_WORKFLOW_RESOURCES" | 
|  | 48 | +envs, err := couler.GetStepEnvs(session) | 
|  | 49 | +if err != nil { | 
|  | 50 | +return "", err | 
|  | 51 | +} | 
|  | 52 | +secretName, secretData, err := couler.GetSecret() | 
|  | 53 | +if err != nil { | 
|  | 54 | +return "", err | 
|  | 55 | +} | 
|  | 56 | +if err := couler.VerifyResources(os.Getenv(workflowResourcesEnv)); err != nil { | 
|  | 57 | +return "", err | 
|  | 58 | +} | 
|  | 59 | +if os.Getenv("SQLFLOW_WORKFLOW_TTL") != "" { | 
|  | 60 | +workflowTTL, err = strconv.Atoi(os.Getenv("SQLFLOW_WORKFLOW_TTL")) | 
|  | 61 | +if err != nil { | 
|  | 62 | +return "", fmt.Errorf("SQLFLOW_WORKFLOW_TTL: %s should be int", os.Getenv("SQLFLOW_WORKFLOW_TTL")) | 
|  | 63 | +} | 
|  | 64 | +} | 
|  | 65 | + | 
|  | 66 | +filler := &coulerFiller{ | 
|  | 67 | +StepList: stepList, | 
|  | 68 | +DataSource: session.DbConnStr, | 
|  | 69 | +StepEnvs: envs, | 
|  | 70 | +WorkflowTTL: workflowTTL, | 
|  | 71 | +SecretName: secretName, | 
|  | 72 | +SecretData: secretData, | 
|  | 73 | +Resources: os.Getenv(workflowResourcesEnv), | 
|  | 74 | +} | 
|  | 75 | +var program bytes.Buffer | 
|  | 76 | +if err := coulerTemplate.Execute(&program, filler); err != nil { | 
|  | 77 | +return "", err | 
|  | 78 | +} | 
|  | 79 | +return program.String(), nil | 
|  | 80 | +} | 
|  | 81 | + | 
|  | 82 | +var coulerCodeTmpl = ` | 
|  | 83 | +import couler.argo as couler | 
|  | 84 | +import json | 
|  | 85 | +import re | 
|  | 86 | +
 | 
|  | 87 | +datasource = "{{ .DataSource }}" | 
|  | 88 | +
 | 
|  | 89 | +step_envs = dict() | 
|  | 90 | +{{range $k, $v := .StepEnvs}}step_envs["{{$k}}"] = '''{{$v}}''' | 
|  | 91 | +{{end}} | 
|  | 92 | +
 | 
|  | 93 | +sqlflow_secret = None | 
|  | 94 | +if "{{.SecretName}}" != "": | 
|  | 95 | +# note(yancey1989): set dry_run to true, just reference the secret meta to generate workflow YAML, | 
|  | 96 | +# we should create the secret before launching sqlflowserver | 
|  | 97 | +secret_data=json.loads('''{{.SecretData}}''') | 
|  | 98 | +sqlflow_secret = couler.secret(secret_data, name="{{ .SecretName }}", dry_run=True) | 
|  | 99 | +
 | 
|  | 100 | +resources = None | 
|  | 101 | +if '''{{.Resources}}''' != "": | 
|  | 102 | + resources=json.loads('''{{.Resources}}''') | 
|  | 103 | +
 | 
|  | 104 | +couler.clean_workflow_after_seconds_finished({{.WorkflowTTL}}) | 
|  | 105 | +
 | 
|  | 106 | +{{ range $ss := .StepList }} | 
|  | 107 | +{{.Code}} | 
|  | 108 | +couler.run_script(image="{{.Image}}", source=step_entry_{{.StepIndex}}, env=step_envs, resources=resources) | 
|  | 109 | +{{end}} | 
|  | 110 | +` | 
|  | 111 | + | 
|  | 112 | +var coulerTemplate = template.Must(template.New("Couler").Parse(coulerCodeTmpl)) | 
0 commit comments