github.com/kubevela/workflow@v0.6.0/pkg/providers/workspace/workspace.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 workspace 18 19 import ( 20 "fmt" 21 "strings" 22 "time" 23 24 monitorContext "github.com/kubevela/pkg/monitor/context" 25 "sigs.k8s.io/kind/pkg/errors" 26 27 "github.com/kubevela/workflow/api/v1alpha1" 28 wfContext "github.com/kubevela/workflow/pkg/context" 29 "github.com/kubevela/workflow/pkg/cue/model" 30 "github.com/kubevela/workflow/pkg/cue/model/value" 31 "github.com/kubevela/workflow/pkg/cue/process" 32 "github.com/kubevela/workflow/pkg/types" 33 ) 34 35 const ( 36 // ProviderName is provider name. 37 ProviderName = "builtin" 38 // ResumeTimeStamp is resume time stamp. 39 ResumeTimeStamp = "resumeTimeStamp" 40 // SuspendTimeStamp is suspend time stamp. 41 SuspendTimeStamp = "suspendTimeStamp" 42 ) 43 44 type provider struct { 45 pCtx process.Context 46 } 47 48 // DoVar get & put variable from context. 49 func (h *provider) DoVar(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error { 50 methodV, err := v.Field("method") 51 if err != nil { 52 return err 53 } 54 method, err := methodV.String() 55 if err != nil { 56 return err 57 } 58 59 pathV, err := v.Field("path") 60 if err != nil { 61 return err 62 } 63 path, err := pathV.String() 64 if err != nil { 65 return err 66 } 67 68 switch method { 69 case "Get": 70 value, err := wfCtx.GetVar(strings.Split(path, ".")...) 71 if err != nil { 72 return err 73 } 74 raw, err := value.String() 75 if err != nil { 76 return err 77 } 78 return v.FillRaw(raw, "value") 79 case "Put": 80 value, err := v.LookupValue("value") 81 if err != nil { 82 return err 83 } 84 return wfCtx.SetVar(value, strings.Split(path, ".")...) 85 } 86 return nil 87 } 88 89 // Wait let workflow wait. 90 func (h *provider) Wait(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error { 91 cv := v.CueValue() 92 if cv.Exists() { 93 ret := cv.LookupPath(value.FieldPath("continue")) 94 if ret.Exists() { 95 isContinue, err := ret.Bool() 96 if err == nil && isContinue { 97 return nil 98 } 99 } 100 } 101 msg, _ := v.GetString("message") 102 act.Wait(msg) 103 return nil 104 } 105 106 // Break let workflow terminate. 107 func (h *provider) Break(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error { 108 var msg string 109 if v != nil { 110 msg, _ = v.GetString("message") 111 } 112 act.Terminate(msg) 113 return nil 114 } 115 116 // Fail let the step fail, its status is failed and reason is Action 117 func (h *provider) Fail(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error { 118 var msg string 119 if v != nil { 120 msg, _ = v.GetString("message") 121 } 122 act.Fail(msg) 123 return nil 124 } 125 126 // Suspend let the step suspend, its status is suspending and reason is Suspend 127 func (h *provider) Suspend(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error { 128 stepID := fmt.Sprint(h.pCtx.GetData(model.ContextStepSessionID)) 129 timestamp := wfCtx.GetMutableValue(stepID, ResumeTimeStamp) 130 var msg string 131 if v != nil { 132 msg, _ = v.GetString("message") 133 if msg == "" { 134 msg = fmt.Sprintf("Suspended by field %s", v.FieldName()) 135 } 136 } 137 if timestamp != "" { 138 t, err := time.Parse(time.RFC3339, timestamp) 139 if err != nil { 140 return errors.Wrap(err, "failed to parse timestamp") 141 } 142 if time.Now().After(t) { 143 act.Resume("") 144 return nil 145 } 146 act.Suspend(msg) 147 return nil 148 } 149 if v != nil { 150 d, _ := v.LookupValue("duration") 151 if d != nil && d.CueValue().Exists() { 152 dur, err := d.CueValue().String() 153 if err != nil { 154 return err 155 } 156 duration, err := time.ParseDuration(dur) 157 if err != nil { 158 return errors.Wrap(err, "failed to parse duration") 159 } 160 wfCtx.SetMutableValue(time.Now().Add(duration).Format(time.RFC3339), stepID, ResumeTimeStamp) 161 } 162 } 163 if ts := wfCtx.GetMutableValue(stepID, v.FieldName(), SuspendTimeStamp); ts != "" { 164 if act.GetStatus().Phase == v1alpha1.WorkflowStepPhaseRunning { 165 // if it is already suspended before and has been resumed, we should not suspend it again. 166 return nil 167 } 168 } else { 169 wfCtx.SetMutableValue(time.Now().Format(time.RFC3339), stepID, v.FieldName(), SuspendTimeStamp) 170 } 171 act.Suspend(msg) 172 return nil 173 } 174 175 // Message writes message to step status, note that the message will be overwritten by the next message. 176 func (h *provider) Message(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act types.Action) error { 177 var msg string 178 if v != nil { 179 msg, _ = v.GetString("message") 180 } 181 act.Message(msg) 182 return nil 183 } 184 185 // Install register handler to provider discover. 186 func Install(p types.Providers, pCtx process.Context) { 187 prd := &provider{ 188 pCtx: pCtx, 189 } 190 p.Register(ProviderName, map[string]types.Handler{ 191 "wait": prd.Wait, 192 "break": prd.Break, 193 "fail": prd.Fail, 194 "message": prd.Message, 195 "var": prd.DoVar, 196 "suspend": prd.Suspend, 197 }) 198 }