1# -*- coding: utf-8 -*- #
2# Copyright 2019 Google LLC. All Rights Reserved.
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"""Wraps an Events Trigger message, making fields more convenient."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import unicode_literals
20
21from apitools.base.protorpclite import protojson
22from googlecloudsdk.api_lib.run import k8s_object
23import six.moves.urllib.parse
24
25_K8S_SERVICE_API_VERSION = 'v1'
26_K8S_SERVICE_KIND = 'Service'
27
28_SERVICE_API_VERSION = 'serving.knative.dev/v1'
29_SERVICE_KIND = 'Service'
30
31EVENT_TYPE_FIELD = 'type'
32# k8s OwnerReference serialized to a json string
33DEPENDENCY_ANNOTATION_FIELD = 'knative.dev/dependency'
34# Annotation to indicate that the namespace should be labeled, which in
35# will create the broker "default" if it does not already exist.
36# The value for this field should only be "enabled" and it should only be set
37# if the trigger's broker is named "default".
38_INJECTION_ANNOTATION_FIELD = 'knative-eventing-injection'
39_INJECTION_BROKER_NAME = 'default'
40# Field placed on both the trigger and source (as a CEOverrdie) to link the
41# resources so the trigger only consumes events from that source
42SOURCE_TRIGGER_LINK_FIELD = 'knsourcetrigger'
43
44
45class Trigger(k8s_object.KubernetesObject):
46  """Wraps an Events Trigger message, making fields more convenient."""
47
48  API_CATEGORY = 'eventing.knative.dev'
49  KIND = 'Trigger'
50  READY_CONDITION = 'Ready'
51  TERMINAL_CONDITIONS = {
52      READY_CONDITION,
53  }
54  FIELD_BLACKLIST = []
55
56  @property
57  def dependency(self):
58    """The knative dependency annotation.
59
60    Returns:
61      ObjectReference of the dependency annotation if one exists, else None.
62    """
63    if DEPENDENCY_ANNOTATION_FIELD not in self.annotations:
64      return None
65    return protojson.decode_message(
66        self._messages.ObjectReference,
67        self.annotations[DEPENDENCY_ANNOTATION_FIELD])
68
69  @dependency.setter
70  def dependency(self, k8s_obj):
71    """Set the knative dependency annotation by passing a k8s_object.KubernetesObject."""
72    self.annotations[DEPENDENCY_ANNOTATION_FIELD] = protojson.encode_message(
73        k8s_obj.AsObjectReference())
74
75  @property
76  def broker(self):
77    return self._m.spec.broker
78
79  @broker.setter
80  def broker(self, value):
81    if value == _INJECTION_BROKER_NAME:
82      self.annotations[_INJECTION_ANNOTATION_FIELD] = 'enabled'
83    self._m.spec.broker = value
84
85  @property
86  def subscriber(self):
87    # TODO(b/147249685): Support ref + relative uri case
88    if self._m.spec.subscriber.uri:
89      return self._m.spec.subscriber.uri
90    return self._m.spec.subscriber.ref.name
91
92  @subscriber.setter
93  def subscriber(self, sink):
94    """Set the subscriber to a Cloud Run service."""
95    if not sink:
96      raise AttributeError('Invalid sink: {}'.format(sink))
97    if ':' not in sink:
98      sink = 'ksvc:' + sink
99    parsed = six.moves.urllib.parse.urlparse(sink)
100
101    if parsed.scheme == 'http' or parsed.scheme == 'https':
102      # URI target
103      self._m.spec.subscriber.uri = sink
104      self._m.spec.subscriber.ref = None
105      return
106    # TODO(b/169444592) Add k8s service support
107    elif parsed.scheme == 'ksvc' or not parsed.scheme:
108      self._m.spec.subscriber.ref.apiVersion = _SERVICE_API_VERSION
109      self._m.spec.subscriber.ref.kind = _SERVICE_KIND
110      self._m.spec.subscriber.ref.name = parsed.path
111    else:
112      raise AttributeError('Invalid sink: {}'.format(sink))
113
114  @property
115  def filter_attributes(self):
116    return k8s_object.ListAsDictionaryWrapper(
117        self._m.spec.filter.attributes.additionalProperties,
118        self._messages.TriggerFilter.AttributesValue.AdditionalProperty,
119        key_field='key',
120        value_field='value')
121