github.com/argoproj/argo-events@v1.9.1/controllers/sensor/validate.go (about)

     1  /*
     2  Copyright 2018 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  
    17  package sensor
    18  
    19  import (
    20  	"fmt"
    21  	"net/http"
    22  	"time"
    23  
    24  	cronlib "github.com/robfig/cron/v3"
    25  
    26  	"github.com/argoproj/argo-events/common"
    27  	eventbusv1alpha1 "github.com/argoproj/argo-events/pkg/apis/eventbus/v1alpha1"
    28  	"github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1"
    29  )
    30  
    31  // ValidateSensor accepts a sensor and performs validation against it
    32  // we return an error so that it can be logged as a message on the sensor status
    33  // the error is ignored by the operation context as subsequent re-queues would produce the same error.
    34  // Exporting this function so that external APIs can use this to validate sensor resource.
    35  func ValidateSensor(s *v1alpha1.Sensor, b *eventbusv1alpha1.EventBus) error {
    36  	if s == nil {
    37  		s.Status.MarkDependenciesNotProvided("InvalidSensor", "nil sensor")
    38  		return fmt.Errorf("nil sensor")
    39  	}
    40  	if b == nil {
    41  		s.Status.MarkDependenciesNotProvided("InvalidEventBus", "nil eventbus")
    42  		return fmt.Errorf("nil eventbus")
    43  	}
    44  	if err := validateDependencies(s.Spec.Dependencies, b); err != nil {
    45  		s.Status.MarkDependenciesNotProvided("InvalidDependencies", err.Error())
    46  		return err
    47  	}
    48  	s.Status.MarkDependenciesProvided()
    49  	err := validateTriggers(s.Spec.Triggers)
    50  	if err != nil {
    51  		s.Status.MarkTriggersNotProvided("InvalidTriggers", err.Error())
    52  		return err
    53  	}
    54  	s.Status.MarkTriggersProvided()
    55  	return nil
    56  }
    57  
    58  // validateTriggers validates triggers
    59  func validateTriggers(triggers []v1alpha1.Trigger) error {
    60  	if len(triggers) < 1 {
    61  		return fmt.Errorf("no triggers found")
    62  	}
    63  
    64  	trigNames := make(map[string]bool)
    65  
    66  	for _, trigger := range triggers {
    67  		if err := validateTriggerTemplate(trigger.Template); err != nil {
    68  			return err
    69  		}
    70  		if _, ok := trigNames[trigger.Template.Name]; ok {
    71  			return fmt.Errorf("duplicate trigger name: %s", trigger.Template.Name)
    72  		}
    73  		trigNames[trigger.Template.Name] = true
    74  		if err := validateTriggerPolicy(&trigger); err != nil {
    75  			return err
    76  		}
    77  		if err := validateTriggerTemplateParameters(&trigger); err != nil {
    78  			return err
    79  		}
    80  	}
    81  	return nil
    82  }
    83  
    84  // validateTriggerTemplate validates trigger template
    85  func validateTriggerTemplate(template *v1alpha1.TriggerTemplate) error {
    86  	if template == nil {
    87  		return fmt.Errorf("trigger template can't be nil")
    88  	}
    89  	if template.Name == "" {
    90  		return fmt.Errorf("trigger must define a name")
    91  	}
    92  	if len(template.ConditionsReset) > 0 {
    93  		for _, c := range template.ConditionsReset {
    94  			if c.ByTime == nil {
    95  				return fmt.Errorf("invalid conditionsReset")
    96  			}
    97  			parser := cronlib.NewParser(cronlib.Minute | cronlib.Hour | cronlib.Dom | cronlib.Month | cronlib.Dow)
    98  			if _, err := parser.Parse(c.ByTime.Cron); err != nil {
    99  				return fmt.Errorf("invalid cron expression %q", c.ByTime.Cron)
   100  			}
   101  			if _, err := time.LoadLocation(c.ByTime.Timezone); err != nil {
   102  				return fmt.Errorf("invalid timezone %q", c.ByTime.Timezone)
   103  			}
   104  		}
   105  	}
   106  	if template.K8s != nil {
   107  		if err := validateK8STrigger(template.K8s); err != nil {
   108  			return fmt.Errorf("trigger for template %s is invalid, %w", template.Name, err)
   109  		}
   110  	}
   111  	if template.ArgoWorkflow != nil {
   112  		if err := validateArgoWorkflowTrigger(template.ArgoWorkflow); err != nil {
   113  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   114  		}
   115  	}
   116  	if template.HTTP != nil {
   117  		if err := validateHTTPTrigger(template.HTTP); err != nil {
   118  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   119  		}
   120  	}
   121  	if template.AWSLambda != nil {
   122  		if err := validateAWSLambdaTrigger(template.AWSLambda); err != nil {
   123  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   124  		}
   125  	}
   126  	if template.Kafka != nil {
   127  		if err := validateKafkaTrigger(template.Kafka); err != nil {
   128  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   129  		}
   130  	}
   131  	if template.NATS != nil {
   132  		if err := validateNATSTrigger(template.NATS); err != nil {
   133  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   134  		}
   135  	}
   136  	if template.Slack != nil {
   137  		if err := validateSlackTrigger(template.Slack); err != nil {
   138  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   139  		}
   140  	}
   141  	if template.OpenWhisk != nil {
   142  		if err := validateOpenWhiskTrigger(template.OpenWhisk); err != nil {
   143  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   144  		}
   145  	}
   146  	if template.CustomTrigger != nil {
   147  		if err := validateCustomTrigger(template.CustomTrigger); err != nil {
   148  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   149  		}
   150  	}
   151  	if template.Email != nil {
   152  		if err := validateEmailTrigger(template.Email); err != nil {
   153  			return fmt.Errorf("template %s is invalid, %w", template.Name, err)
   154  		}
   155  	}
   156  	return nil
   157  }
   158  
   159  // validateK8STrigger validates a kubernetes trigger
   160  func validateK8STrigger(trigger *v1alpha1.StandardK8STrigger) error {
   161  	if trigger == nil {
   162  		return fmt.Errorf("k8s trigger can't be nil")
   163  	}
   164  	if trigger.Source == nil {
   165  		return fmt.Errorf("k8s trigger does not contain an absolute action")
   166  	}
   167  
   168  	switch trigger.Operation {
   169  	case "", v1alpha1.Create, v1alpha1.Patch, v1alpha1.Update, v1alpha1.Delete:
   170  
   171  	default:
   172  		return fmt.Errorf("unknown operation type %s", string(trigger.Operation))
   173  	}
   174  	if trigger.Parameters != nil {
   175  		for i, parameter := range trigger.Parameters {
   176  			if err := validateTriggerParameter(&parameter); err != nil {
   177  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   178  			}
   179  		}
   180  	}
   181  	return nil
   182  }
   183  
   184  // validateArgoWorkflowTrigger validates an Argo workflow trigger
   185  func validateArgoWorkflowTrigger(trigger *v1alpha1.ArgoWorkflowTrigger) error {
   186  	if trigger == nil {
   187  		return fmt.Errorf("argoWorkflow trigger can't be nil")
   188  	}
   189  	if trigger.Source == nil {
   190  		return fmt.Errorf("argoWorkflow trigger does not contain an absolute action")
   191  	}
   192  
   193  	switch trigger.Operation {
   194  	case v1alpha1.Submit, v1alpha1.SubmitFrom, v1alpha1.Suspend, v1alpha1.Retry, v1alpha1.Resume, v1alpha1.Resubmit, v1alpha1.Terminate, v1alpha1.Stop:
   195  	default:
   196  		return fmt.Errorf("unknown operation type %s", string(trigger.Operation))
   197  	}
   198  	if trigger.Parameters != nil {
   199  		for i, parameter := range trigger.Parameters {
   200  			if err := validateTriggerParameter(&parameter); err != nil {
   201  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   202  			}
   203  		}
   204  	}
   205  	return nil
   206  }
   207  
   208  // validateHTTPTrigger validates the HTTP trigger
   209  func validateHTTPTrigger(trigger *v1alpha1.HTTPTrigger) error {
   210  	if trigger == nil {
   211  		return fmt.Errorf("HTTP trigger for can't be nil")
   212  	}
   213  	if trigger.URL == "" {
   214  		return fmt.Errorf("server URL is not specified")
   215  	}
   216  	if trigger.Method != "" {
   217  		switch trigger.Method {
   218  		case http.MethodGet, http.MethodDelete, http.MethodPatch, http.MethodPost, http.MethodPut:
   219  		default:
   220  			return fmt.Errorf("only GET, DELETE, PATCH, POST and PUT methods are supported")
   221  		}
   222  	}
   223  	if trigger.Parameters != nil {
   224  		for i, parameter := range trigger.Parameters {
   225  			if err := validateTriggerParameter(&parameter); err != nil {
   226  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   227  			}
   228  		}
   229  	}
   230  	if trigger.Payload != nil {
   231  		for i, p := range trigger.Payload {
   232  			if err := validateTriggerParameter(&p); err != nil {
   233  				return fmt.Errorf("payload index: %d. err: %w", i, err)
   234  			}
   235  		}
   236  	}
   237  	return nil
   238  }
   239  
   240  // validateOpenWhiskTrigger validates the OpenWhisk trigger
   241  func validateOpenWhiskTrigger(trigger *v1alpha1.OpenWhiskTrigger) error {
   242  	if trigger == nil {
   243  		return fmt.Errorf("openwhisk trigger for can't be nil")
   244  	}
   245  	if trigger.ActionName == "" {
   246  		return fmt.Errorf("action name is not specified")
   247  	}
   248  	if trigger.Host == "" {
   249  		return fmt.Errorf("host URL is not specified")
   250  	}
   251  	if trigger.AuthToken != nil {
   252  		if trigger.AuthToken.Name == "" || trigger.AuthToken.Key == "" {
   253  			return fmt.Errorf("auth token key and name must be specified")
   254  		}
   255  	}
   256  	if trigger.Parameters != nil {
   257  		for i, parameter := range trigger.Parameters {
   258  			if err := validateTriggerParameter(&parameter); err != nil {
   259  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   260  			}
   261  		}
   262  	}
   263  	if trigger.Payload == nil {
   264  		return fmt.Errorf("payload parameters are not specified")
   265  	}
   266  	if trigger.Payload != nil {
   267  		for i, p := range trigger.Payload {
   268  			if err := validateTriggerParameter(&p); err != nil {
   269  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   270  			}
   271  		}
   272  	}
   273  	return nil
   274  }
   275  
   276  // validateAWSLambdaTrigger validates the AWS Lambda trigger
   277  func validateAWSLambdaTrigger(trigger *v1alpha1.AWSLambdaTrigger) error {
   278  	if trigger == nil {
   279  		return fmt.Errorf("openfaas trigger for can't be nil")
   280  	}
   281  	if trigger.FunctionName == "" {
   282  		return fmt.Errorf("function name is not specified")
   283  	}
   284  	if trigger.Region == "" {
   285  		return fmt.Errorf("region in not specified")
   286  	}
   287  	if trigger.Payload == nil {
   288  		return fmt.Errorf("payload parameters are not specified")
   289  	}
   290  	if trigger.Parameters != nil {
   291  		for i, parameter := range trigger.Parameters {
   292  			if err := validateTriggerParameter(&parameter); err != nil {
   293  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   294  			}
   295  		}
   296  	}
   297  	if trigger.Payload != nil {
   298  		for i, p := range trigger.Payload {
   299  			if err := validateTriggerParameter(&p); err != nil {
   300  				return fmt.Errorf("payload index: %d. err: %w", i, err)
   301  			}
   302  		}
   303  	}
   304  	return nil
   305  }
   306  
   307  // validateKafkaTrigger validates the kafka trigger.
   308  func validateKafkaTrigger(trigger *v1alpha1.KafkaTrigger) error {
   309  	if trigger == nil {
   310  		return fmt.Errorf("trigger can't be nil")
   311  	}
   312  	if trigger.URL == "" {
   313  		return fmt.Errorf("broker url must not be empty")
   314  	}
   315  	if trigger.Payload == nil {
   316  		return fmt.Errorf("payload must not be empty")
   317  	}
   318  	if trigger.Topic == "" {
   319  		return fmt.Errorf("topic must not be empty")
   320  	}
   321  	if trigger.Payload != nil {
   322  		for i, p := range trigger.Payload {
   323  			if err := validateTriggerParameter(&p); err != nil {
   324  				return fmt.Errorf("payload index: %d. err: %w", i, err)
   325  			}
   326  		}
   327  	}
   328  	return nil
   329  }
   330  
   331  // validateNATSTrigger validates the NATS trigger.
   332  func validateNATSTrigger(trigger *v1alpha1.NATSTrigger) error {
   333  	if trigger == nil {
   334  		return fmt.Errorf("trigger can't be nil")
   335  	}
   336  	if trigger.URL == "" {
   337  		return fmt.Errorf("nats server url can't be empty")
   338  	}
   339  	if trigger.Subject == "" {
   340  		return fmt.Errorf("nats subject can't be empty")
   341  	}
   342  	if trigger.Payload == nil {
   343  		return fmt.Errorf("payload can't be nil")
   344  	}
   345  	if trigger.Payload != nil {
   346  		for i, p := range trigger.Payload {
   347  			if err := validateTriggerParameter(&p); err != nil {
   348  				return fmt.Errorf("payload index: %d. err: %w", i, err)
   349  			}
   350  		}
   351  	}
   352  	return nil
   353  }
   354  
   355  // validateSlackTrigger validates the Slack trigger.
   356  func validateSlackTrigger(trigger *v1alpha1.SlackTrigger) error {
   357  	if trigger == nil {
   358  		return fmt.Errorf("trigger can't be nil")
   359  	}
   360  	if trigger.SlackToken == nil {
   361  		return fmt.Errorf("slack token can't be empty")
   362  	}
   363  	if trigger.Parameters != nil {
   364  		for i, parameter := range trigger.Parameters {
   365  			if err := validateTriggerParameter(&parameter); err != nil {
   366  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   367  			}
   368  		}
   369  	}
   370  	return nil
   371  }
   372  
   373  // validateEmailTrigger validates the Email trigger
   374  func validateEmailTrigger(trigger *v1alpha1.EmailTrigger) error {
   375  	if trigger == nil {
   376  		return fmt.Errorf("trigger can't be nil")
   377  	}
   378  	if trigger.Host == "" {
   379  		return fmt.Errorf("host can't be empty")
   380  	}
   381  	if 0 > trigger.Port || trigger.Port > 65535 {
   382  		return fmt.Errorf("port: %v, port should be between 0-65535", trigger.Port)
   383  	}
   384  	if trigger.Parameters != nil {
   385  		for i, parameter := range trigger.Parameters {
   386  			if err := validateTriggerParameter(&parameter); err != nil {
   387  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   388  			}
   389  		}
   390  	}
   391  	return nil
   392  }
   393  
   394  // validateCustomTrigger validates the custom trigger.
   395  func validateCustomTrigger(trigger *v1alpha1.CustomTrigger) error {
   396  	if trigger == nil {
   397  		return fmt.Errorf("custom trigger for can't be nil")
   398  	}
   399  	if trigger.ServerURL == "" {
   400  		return fmt.Errorf("custom trigger gRPC server url is not defined")
   401  	}
   402  	if trigger.Spec == nil {
   403  		return fmt.Errorf("trigger body can't be empty")
   404  	}
   405  	if trigger.Secure {
   406  		if trigger.CertSecret == nil {
   407  			return fmt.Errorf("certSecret can't be nil when the trigger server connection is secure")
   408  		}
   409  	}
   410  	if trigger.Parameters != nil {
   411  		for i, parameter := range trigger.Parameters {
   412  			if err := validateTriggerParameter(&parameter); err != nil {
   413  				return fmt.Errorf("resource parameter index: %d. err: %w", i, err)
   414  			}
   415  		}
   416  	}
   417  	return nil
   418  }
   419  
   420  // validateTriggerTemplateParameters validates resource and template parameters if any
   421  func validateTriggerTemplateParameters(trigger *v1alpha1.Trigger) error {
   422  	if trigger.Parameters != nil {
   423  		for i, parameter := range trigger.Parameters {
   424  			if err := validateTriggerParameter(&parameter); err != nil {
   425  				return fmt.Errorf("template parameter index: %d. err: %w", i, err)
   426  			}
   427  		}
   428  	}
   429  	return nil
   430  }
   431  
   432  // validateTriggerParameter validates a trigger parameter
   433  func validateTriggerParameter(parameter *v1alpha1.TriggerParameter) error {
   434  	if parameter.Src == nil {
   435  		return fmt.Errorf("parameter source can't be empty")
   436  	}
   437  	if parameter.Src.DependencyName == "" {
   438  		return fmt.Errorf("parameter dependency name can't be empty")
   439  	}
   440  	if parameter.Dest == "" {
   441  		return fmt.Errorf("parameter destination can't be empty")
   442  	}
   443  
   444  	switch op := parameter.Operation; op {
   445  	case v1alpha1.TriggerParameterOpAppend:
   446  	case v1alpha1.TriggerParameterOpOverwrite:
   447  	case v1alpha1.TriggerParameterOpPrepend:
   448  	case v1alpha1.TriggerParameterOpNone:
   449  	default:
   450  		return fmt.Errorf("parameter operation %+v is invalid", op)
   451  	}
   452  
   453  	return nil
   454  }
   455  
   456  // perform a check to see that each event dependency is in correct format and has valid filters set if any
   457  func validateDependencies(eventDependencies []v1alpha1.EventDependency, b *eventbusv1alpha1.EventBus) error {
   458  	if len(eventDependencies) < 1 {
   459  		return fmt.Errorf("no event dependencies found")
   460  	}
   461  
   462  	comboKeys := make(map[string]bool)
   463  	for _, dep := range eventDependencies {
   464  		if dep.Name == "" {
   465  			return fmt.Errorf("event dependency must define a name")
   466  		}
   467  		if dep.EventSourceName == "" {
   468  			return fmt.Errorf("event dependency must define the EventSourceName")
   469  		}
   470  
   471  		if dep.EventName == "" {
   472  			return fmt.Errorf("event dependency must define the EventName")
   473  		}
   474  		if b.Spec.NATS != nil {
   475  			// For STAN, EventSourceName + EventName can not be referenced more than once in one Sensor object.
   476  			comboKey := fmt.Sprintf("%s-$$$-%s", dep.EventSourceName, dep.EventName)
   477  			if _, existing := comboKeys[comboKey]; existing {
   478  				return fmt.Errorf("event '%s' from EventSource '%s' is referenced for more than one dependency in this Sensor object", dep.EventName, dep.EventSourceName)
   479  			}
   480  			comboKeys[comboKey] = true
   481  		}
   482  
   483  		if err := validateEventFilter(dep.Filters); err != nil {
   484  			return err
   485  		}
   486  
   487  		if err := validateLogicalOperator(dep.FiltersLogicalOperator); err != nil {
   488  			return err
   489  		}
   490  	}
   491  	return nil
   492  }
   493  
   494  // validateLogicalOperator verifies that the logical operator in input is equal to a supported value
   495  func validateLogicalOperator(logOp v1alpha1.LogicalOperator) error {
   496  	if logOp != v1alpha1.AndLogicalOperator &&
   497  		logOp != v1alpha1.OrLogicalOperator &&
   498  		logOp != v1alpha1.EmptyLogicalOperator {
   499  		return fmt.Errorf("logical operator %s not supported", logOp)
   500  	}
   501  	return nil
   502  }
   503  
   504  // validateComparator verifies that the comparator in input is equal to a supported value
   505  func validateComparator(comp v1alpha1.Comparator) error {
   506  	if comp != v1alpha1.GreaterThanOrEqualTo &&
   507  		comp != v1alpha1.GreaterThan &&
   508  		comp != v1alpha1.EqualTo &&
   509  		comp != v1alpha1.NotEqualTo &&
   510  		comp != v1alpha1.LessThan &&
   511  		comp != v1alpha1.LessThanOrEqualTo &&
   512  		comp != v1alpha1.EmptyComparator {
   513  		return fmt.Errorf("comparator %s not supported", comp)
   514  	}
   515  
   516  	return nil
   517  }
   518  
   519  // validateEventFilter for a sensor
   520  func validateEventFilter(filter *v1alpha1.EventDependencyFilter) error {
   521  	if filter == nil {
   522  		return nil
   523  	}
   524  
   525  	if err := validateLogicalOperator(filter.ExprLogicalOperator); err != nil {
   526  		return err
   527  	}
   528  
   529  	if err := validateLogicalOperator(filter.DataLogicalOperator); err != nil {
   530  		return err
   531  	}
   532  
   533  	if filter.Exprs != nil {
   534  		for _, expr := range filter.Exprs {
   535  			if err := validateEventExprFilter(&expr); err != nil {
   536  				return err
   537  			}
   538  		}
   539  	}
   540  
   541  	if filter.Data != nil {
   542  		for _, data := range filter.Data {
   543  			if err := validateEventDataFilter(&data); err != nil {
   544  				return err
   545  			}
   546  		}
   547  	}
   548  
   549  	if filter.Context != nil {
   550  		if err := validateEventCtxFilter(filter.Context); err != nil {
   551  			return err
   552  		}
   553  	}
   554  
   555  	if filter.Time != nil {
   556  		if err := validateEventTimeFilter(filter.Time); err != nil {
   557  			return err
   558  		}
   559  	}
   560  	return nil
   561  }
   562  
   563  // validateEventExprFilter validates context filter
   564  func validateEventExprFilter(exprFilter *v1alpha1.ExprFilter) error {
   565  	if exprFilter.Expr == "" ||
   566  		len(exprFilter.Fields) == 0 {
   567  		return fmt.Errorf("one of expr filters is not valid (expr and fields must be not empty)")
   568  	}
   569  
   570  	for _, fld := range exprFilter.Fields {
   571  		if fld.Path == "" || fld.Name == "" {
   572  			return fmt.Errorf("one of expr filters is not valid (path and name in a field must be not empty)")
   573  		}
   574  	}
   575  
   576  	return nil
   577  }
   578  
   579  // validateEventDataFilter validates context filter
   580  func validateEventDataFilter(dataFilter *v1alpha1.DataFilter) error {
   581  	if dataFilter.Comparator != v1alpha1.EmptyComparator {
   582  		if err := validateComparator(dataFilter.Comparator); err != nil {
   583  			return err
   584  		}
   585  	}
   586  
   587  	if dataFilter.Path == "" ||
   588  		dataFilter.Type == "" ||
   589  		len(dataFilter.Value) == 0 {
   590  		return fmt.Errorf("one of data filters is not valid (type, path and value must be not empty)")
   591  	}
   592  
   593  	for _, val := range dataFilter.Value {
   594  		if val == "" {
   595  			return fmt.Errorf("one of data filters is not valid (value must be not empty)")
   596  		}
   597  	}
   598  
   599  	return nil
   600  }
   601  
   602  // validateEventCtxFilter validates context filter
   603  func validateEventCtxFilter(ctxFilter *v1alpha1.EventContext) error {
   604  	if ctxFilter.Type == "" &&
   605  		ctxFilter.Subject == "" &&
   606  		ctxFilter.Source == "" &&
   607  		ctxFilter.DataContentType == "" {
   608  		return fmt.Errorf("no fields specified in ctx filter (aka all events will be discarded)")
   609  	}
   610  	return nil
   611  }
   612  
   613  // validateEventTimeFilter validates time filter
   614  func validateEventTimeFilter(timeFilter *v1alpha1.TimeFilter) error {
   615  	now := time.Now().UTC()
   616  
   617  	// Parse start and stop
   618  	startTime, startErr := common.ParseTime(timeFilter.Start, now)
   619  	if startErr != nil {
   620  		return startErr
   621  	}
   622  	stopTime, stopErr := common.ParseTime(timeFilter.Stop, now)
   623  	if stopErr != nil {
   624  		return stopErr
   625  	}
   626  
   627  	if stopTime.Equal(startTime) {
   628  		return fmt.Errorf("invalid event time filter: stop '%s' is equal to start '%s", timeFilter.Stop, timeFilter.Start)
   629  	}
   630  	return nil
   631  }
   632  
   633  // validateTriggerPolicy validates a trigger policy
   634  func validateTriggerPolicy(trigger *v1alpha1.Trigger) error {
   635  	if trigger.Policy == nil {
   636  		return nil
   637  	}
   638  	if trigger.Template.K8s != nil {
   639  		return validateK8sTriggerPolicy(trigger.Policy.K8s)
   640  	}
   641  	if trigger.Template.ArgoWorkflow != nil {
   642  		return validateK8sTriggerPolicy(trigger.Policy.K8s)
   643  	}
   644  	if trigger.Template.HTTP != nil {
   645  		return validateStatusPolicy(trigger.Policy.Status)
   646  	}
   647  	if trigger.Template.AWSLambda != nil {
   648  		return validateStatusPolicy(trigger.Policy.Status)
   649  	}
   650  	return nil
   651  }
   652  
   653  // validateK8sTriggerPolicy validates a k8s trigger policy
   654  func validateK8sTriggerPolicy(policy *v1alpha1.K8SResourcePolicy) error {
   655  	if policy == nil {
   656  		return nil
   657  	}
   658  	if policy.Labels == nil {
   659  		return fmt.Errorf("resource labels are not specified")
   660  	}
   661  	return nil
   662  }
   663  
   664  // validateStatusPolicy validates a http trigger policy
   665  func validateStatusPolicy(policy *v1alpha1.StatusPolicy) error {
   666  	if policy == nil {
   667  		return nil
   668  	}
   669  	if policy.Allow == nil {
   670  		return fmt.Errorf("list of allowed response status is not specified")
   671  	}
   672  	return nil
   673  }