github.com/argoproj/argo-events@v1.9.1/sensors/triggers/apache-openwhisk/apache-openwhisk.go (about) 1 /* 2 Copyright 2020 BlackRock, Inc. 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 package apache_openwhisk 17 18 import ( 19 "context" 20 "encoding/json" 21 "fmt" 22 "net/http" 23 24 "github.com/apache/openwhisk-client-go/whisk" 25 "go.uber.org/zap" 26 27 "github.com/argoproj/argo-events/common" 28 "github.com/argoproj/argo-events/common/logging" 29 apicommon "github.com/argoproj/argo-events/pkg/apis/common" 30 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1" 31 "github.com/argoproj/argo-events/sensors/policy" 32 "github.com/argoproj/argo-events/sensors/triggers" 33 ) 34 35 // TriggerImpl implements the Trigger interface for OpenWhisk trigger. 36 type TriggerImpl struct { 37 // OpenWhiskClient is OpenWhisk API client 38 OpenWhiskClient *whisk.Client 39 // Sensor object 40 Sensor *v1alpha1.Sensor 41 // Trigger definition 42 Trigger *v1alpha1.Trigger 43 // logger to log stuff 44 Logger *zap.SugaredLogger 45 } 46 47 // NewTriggerImpl returns a new TriggerImpl 48 func NewTriggerImpl(sensor *v1alpha1.Sensor, trigger *v1alpha1.Trigger, openWhiskClients common.StringKeyedMap[*whisk.Client], logger *zap.SugaredLogger) (*TriggerImpl, error) { 49 openwhisktrigger := trigger.Template.OpenWhisk 50 51 client, ok := openWhiskClients.Load(trigger.Template.Name) 52 if !ok { 53 logger.Debugw("OpenWhisk trigger value", zap.Any("name", trigger.Template.Name), zap.Any("trigger", *trigger.Template.OpenWhisk)) 54 logger.Infow("instantiating OpenWhisk client", zap.Any("trigger-name", trigger.Template.Name)) 55 56 config, err := whisk.GetDefaultConfig() 57 if err != nil { 58 return nil, fmt.Errorf("failed to get default configuration, %w", err) 59 } 60 61 config.Host = openwhisktrigger.Host 62 63 if openwhisktrigger.AuthToken != nil { 64 token, err := common.GetSecretFromVolume(openwhisktrigger.AuthToken) 65 if err != nil { 66 return nil, fmt.Errorf("failed to retrieve auth token, %w", err) 67 } 68 config.AuthToken = token 69 } 70 71 if openwhisktrigger.Namespace != "" { 72 config.Namespace = openwhisktrigger.Namespace 73 } 74 if openwhisktrigger.Version != "" { 75 config.Version = openwhisktrigger.Version 76 } 77 78 logger.Debugw("configuration for OpenWhisk client", zap.Any("config", *config)) 79 80 client, err = whisk.NewClient(http.DefaultClient, config) 81 if err != nil { 82 return nil, fmt.Errorf("failed to instantiate OpenWhisk client, %w", err) 83 } 84 85 openWhiskClients.Store(trigger.Template.Name, client) 86 } 87 88 return &TriggerImpl{ 89 OpenWhiskClient: client, 90 Sensor: sensor, 91 Trigger: trigger, 92 Logger: logger.With(logging.LabelTriggerType, apicommon.OpenWhiskTrigger), 93 }, nil 94 } 95 96 // GetTriggerType returns the type of the trigger 97 func (t *TriggerImpl) GetTriggerType() apicommon.TriggerType { 98 return apicommon.OpenWhiskTrigger 99 } 100 101 // FetchResource fetches the trigger. As the OpenWhisk trigger simply executes a http request, there 102 // is no need to fetch any resource from external source 103 func (t *TriggerImpl) FetchResource(ctx context.Context) (interface{}, error) { 104 return t.Trigger.Template.OpenWhisk, nil 105 } 106 107 // ApplyResourceParameters applies parameters to the trigger resource 108 func (t *TriggerImpl) ApplyResourceParameters(events map[string]*v1alpha1.Event, resource interface{}) (interface{}, error) { 109 fetchedResource, ok := resource.(*v1alpha1.OpenWhiskTrigger) 110 if !ok { 111 return nil, fmt.Errorf("failed to interpret the fetched trigger resource") 112 } 113 114 resourceBytes, err := json.Marshal(fetchedResource) 115 if err != nil { 116 return nil, fmt.Errorf("failed to marshal the OpenWhisk trigger resource, %w", err) 117 } 118 parameters := fetchedResource.Parameters 119 if parameters != nil { 120 updatedResourceBytes, err := triggers.ApplyParams(resourceBytes, parameters, events) 121 if err != nil { 122 return nil, err 123 } 124 var openwhisktrigger *v1alpha1.OpenWhiskTrigger 125 if err := json.Unmarshal(updatedResourceBytes, &openwhisktrigger); err != nil { 126 return nil, fmt.Errorf("failed to unmarshal the updated OpenWhisk trigger resource after applying resource parameters, %w", err) 127 } 128 129 t.Logger.Debugw("applied parameters to the OpenWhisk trigger", zap.Any("name", t.Trigger.Template.Name), zap.Any("trigger", *openwhisktrigger)) 130 131 return openwhisktrigger, nil 132 } 133 134 return resource, nil 135 } 136 137 // Execute executes the trigger 138 func (t *TriggerImpl) Execute(ctx context.Context, events map[string]*v1alpha1.Event, resource interface{}) (interface{}, error) { 139 var payload []byte 140 var err error 141 142 openwhisktrigger, ok := resource.(*v1alpha1.OpenWhiskTrigger) 143 if !ok { 144 return nil, fmt.Errorf("failed to interpret the OpenWhisk trigger resource") 145 } 146 147 if openwhisktrigger.Payload != nil { 148 payload, err = triggers.ConstructPayload(events, openwhisktrigger.Payload) 149 if err != nil { 150 return nil, err 151 } 152 153 t.Logger.Debugw("payload for the OpenWhisk action invocation", zap.Any("name", t.Trigger.Template.Name), zap.Any("payload", string(payload))) 154 } 155 156 response, status, err := t.OpenWhiskClient.Actions.Invoke(openwhisktrigger.ActionName, payload, true, true) 157 if err != nil { 158 return nil, fmt.Errorf("failed to invoke action %s, %w", openwhisktrigger.ActionName, err) 159 } 160 161 t.Logger.Debugw("response for the OpenWhisk action invocation", zap.Any("name", t.Trigger.Template.Name), zap.Any("response", response)) 162 163 return status, nil 164 } 165 166 // ApplyPolicy applies policy on the trigger 167 func (t *TriggerImpl) ApplyPolicy(ctx context.Context, resource interface{}) error { 168 if t.Trigger.Policy == nil || t.Trigger.Policy.Status == nil || t.Trigger.Policy.Status.Allow == nil { 169 return nil 170 } 171 response, ok := resource.(*http.Response) 172 if !ok { 173 return fmt.Errorf("failed to interpret the trigger execution response") 174 } 175 176 p := policy.NewStatusPolicy(response.StatusCode, t.Trigger.Policy.Status.GetAllow()) 177 178 return p.ApplyPolicy(ctx) 179 }